home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / bash-1.12 / dist / subst.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-11-26  |  82.1 KB  |  3,408 lines

  1. /* substitutions.c -- The part of the shell that does parameter,
  2.    command, and globbing substitutions. */
  3.  
  4. /* Copyright (C) 1987,1989 Free Software Foundation, Inc.
  5.  
  6. This file is part of GNU Bash, the Bourne Again SHell.
  7.  
  8. Bash is free software; you can redistribute it and/or modify it under
  9. the terms of the GNU General Public License as published by the Free
  10. Software Foundation; either version 1, or (at your option) any later
  11. version.
  12.  
  13. Bash is distributed in the hope that it will be useful, but WITHOUT ANY
  14. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16. for more details.
  17.  
  18. You should have received a copy of the GNU General Public License along
  19. with Bash; see the file COPYING.  If not, write to the Free Software
  20. Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
  21.  
  22. #include <stdio.h>
  23. #include <sys/types.h>
  24. #include <pwd.h>
  25. #include <signal.h>
  26. #include <string.h>
  27. #include "shell.h"
  28. #include "flags.h"
  29. #include "alias.h"
  30. #include "jobs.h"
  31. #include "filecntl.h"
  32. #include <readline/history.h>
  33. #include <glob/fnmatch.h>
  34.  
  35. /* The size that strings change by. */
  36. #define DEFAULT_ARRAY_SIZE 512
  37.  
  38. /* How to quote and dequote the character C. */
  39. #define QUOTE_CHAR(c)   ((unsigned char)(c) | 0x80)
  40. #define DEQUOTE_CHAR(c) ((unsigned char)(c) & 0x7f)
  41. #define QUOTED_CHAR(c)  ((unsigned char)(c) > 0x7f)
  42.  
  43. /* Process ID of the last command executed within command substitution. */
  44. pid_t last_command_subst_pid = NO_PID;
  45.  
  46. /* Some forward declarations. */
  47.  
  48. extern WORD_LIST *expand_string (), *expand_word (), *list_string ();
  49. extern char *string_list ();
  50. extern WORD_DESC *make_word ();
  51. extern WORD_DESC *copy_word ();
  52. extern WORD_LIST *copy_word_list();
  53.  
  54. static WORD_LIST *expand_string_internal (), *expand_words_internal ();
  55. static char *quote_string (), *dequote_string ();
  56. static int unquoted_substring ();
  57. static void quote_list ();
  58.  
  59. /* **************************************************************** */
  60. /*                                    */
  61. /*            Utility Functions                */
  62. /*                                    */
  63. /* **************************************************************** */
  64.  
  65. /* Cons a new string from STRING starting at START and ending at END,
  66.    not including END. */
  67. char *
  68. substring (string, start, end)
  69.      char *string;
  70.      int start, end;
  71. {
  72.   register int len = end - start;
  73.   register char *result = (char *)xmalloc (len + 1);
  74.  
  75.   strncpy (result, string + start, len);
  76.   result[len] = '\0';
  77.   return (result);
  78. }
  79.  
  80. /* Just like string_extract, but doesn't hack backslashes or any of
  81.    that other stuff. */
  82. char *
  83. string_extract_verbatim (string, sindex, charlist)
  84.      char *string, *charlist;
  85.      int *sindex;
  86. {
  87.   register int i = *sindex;
  88.   int c;
  89.   char *temp;
  90.  
  91.   while ((c = string[i]) && (!member (c, charlist))) i++;
  92.   temp = (char *)xmalloc (1 + (i - *sindex));
  93.   strncpy (temp, string + (*sindex), i - (*sindex));
  94.   temp[i - (*sindex)] = '\0';
  95.   *sindex = i;
  96.   return (temp);
  97. }
  98.  
  99. /* Extract a substring from STRING, starting at SINDEX and ending with
  100.    one of the characters in CHARLIST.  Don't make the ending character
  101.    part of the string.  Leave SINDEX pointing at the ending character.
  102.    Understand about backslashes in the string. */
  103. char *
  104. string_extract (string, sindex, charlist)
  105.      char *string, *charlist;
  106.      int *sindex;
  107. {
  108.   register int c, i = *sindex;
  109.   char *temp;
  110.  
  111.   while (c = string[i]) {
  112.     if (c == '\\')
  113.       if (string[i + 1])
  114.     i++;
  115.       else
  116.     break;
  117.     else
  118.       if (member (c, charlist))
  119.     break;
  120.     i++;
  121.   }
  122.   temp = (char *)xmalloc (1 + (i - *sindex));
  123.   strncpy (temp, string + (*sindex), i - (*sindex));
  124.   temp[i - (*sindex)] = '\0';
  125.   *sindex = i;
  126.   return (temp);
  127. }
  128.  
  129. /* Remove backslashes which are quoting backquotes from STRING.  Modifies
  130.    STRING, and returns a pointer to it. */
  131. char *
  132. de_backslash (string)
  133.      char *string;
  134. {
  135.   register int i, l = strlen (string);
  136.  
  137.   for (i = 0; i < l; i++)
  138.     if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' ||
  139.                   string[i + 1] == '$'))
  140.       strcpy (&string[i], &string[i + 1]);
  141.   return (string);
  142. }
  143.  
  144. /* Replace instances of \! in a string with !. */
  145. void
  146. unquote_bang (string)
  147.      char *string;
  148. {
  149.   register int i, j;
  150.   register char *temp;
  151.  
  152.   temp = (char *)alloca (1 + strlen (string));
  153.  
  154.   for (i = 0, j = 0; (temp[j] = string[i]); i++, j++)
  155.     {
  156.       if (string[i] == '\\' && string[i + 1] == '!')
  157.     {
  158.       temp[j] = '!';
  159.       i++;
  160.     }
  161.     }
  162.   strcpy (string, temp);
  163. }
  164.  
  165. /* Extract the $( construct in STRING, and return a new string.
  166.    Start extracting at (SINDEX) as if we had just seen "$(".
  167.    Make (SINDEX) get the position just after the matching ")". */
  168. char *
  169. extract_command_subst (string, sindex)
  170.      char *string;
  171.      int *sindex;
  172. {
  173.   char *extract_delimited_string ();
  174.  
  175.   return (extract_delimited_string (string, sindex, "$(", "(", ")"));
  176. }
  177.  
  178. /* Extract the $[ construct in STRING, and return a new string.
  179.    Start extracting at (SINDEX) as if we had just seen "$[".
  180.    Make (SINDEX) get the position just after the matching "]".
  181.  
  182.    Strictly speaking, according to the letter of POSIX.2, arithmetic
  183.    substitutions cannot be nested.  This code allows nesting, however,
  184.    and it is fully implemented. */
  185. char *
  186. extract_arithmetic_subst (string, sindex)
  187.      char *string;
  188.      int *sindex;
  189. {
  190.   char *extract_delimited_string ();
  191.  
  192.   return (extract_delimited_string (string, sindex, "$[", "[", "]"));
  193. }
  194.  
  195. /* Extract and create a new string from the contents of STRING, a
  196.    character string delimited with OPENER and CLOSER.  SINDEX is
  197.    the address of an int describing the current offset in STRING;
  198.    it should point to just after the first OPENER found.  On exit,
  199.    SINDEX gets the position just after the matching CLOSER.  If
  200.    OPENER is more than a single character, ALT_OPENER, if non-null,
  201.    contains a character string that can also match CLOSER and thus
  202.    needs to be skipped. */
  203. char *
  204. extract_delimited_string (string, sindex, opener, alt_opener, closer)
  205.      char *string;
  206.      int *sindex;
  207.      char *opener, *alt_opener, *closer;
  208. {
  209.   register int i, c, l;
  210.   int pass_character, nesting_level;
  211.   int delimiter, delimited_nesting_level;
  212.   int len_closer, len_opener, len_alt_opener;
  213.   char *result;
  214.  
  215.   len_opener = strlen (opener);
  216.   len_alt_opener = alt_opener ? strlen (alt_opener) : 0;
  217.   len_closer = strlen (closer);
  218.  
  219.   pass_character = delimiter = delimited_nesting_level = 0;
  220.  
  221.   nesting_level = 1;
  222.  
  223.   for (i = *sindex; c = string[i]; i++)
  224.     {
  225.       if (pass_character)
  226.     {
  227.       pass_character = 0;
  228.       continue;
  229.     }
  230.  
  231.       if (c == '\\')
  232.     {
  233.       if ((delimiter == '"') &&
  234.           (member (string[i + 1], slashify_in_quotes)))
  235.         {
  236.           pass_character++;
  237.           continue;
  238.         }
  239.     }
  240.  
  241.       if (!delimiter || delimiter == '"')
  242.     {
  243.       if (strncmp (string + i, opener, len_opener) == 0)
  244.         {
  245.           if (!delimiter)
  246.         nesting_level++;
  247.           else
  248.         delimited_nesting_level++;
  249.  
  250.           i += len_opener - 1;
  251.           continue;
  252.         }
  253.  
  254.       if (len_alt_opener &&
  255.           strncmp (string + i, alt_opener, len_alt_opener) == 0)
  256.         {
  257.           if (!delimiter)
  258.         nesting_level++;
  259.           else
  260.         delimited_nesting_level++;
  261.  
  262.           i += len_alt_opener - 1;
  263.           continue;
  264.         }
  265.  
  266.       if (strncmp (string + i, closer, len_closer) == 0)
  267.         {
  268.           i += len_closer - 1;
  269.  
  270.           if (delimiter && delimited_nesting_level)
  271.         delimited_nesting_level--;
  272.  
  273.           if (!delimiter)
  274.         {
  275.           nesting_level--;
  276.           if (nesting_level == 0)
  277.             break;
  278.         }
  279.         }
  280.     }
  281.  
  282.       if (delimiter)
  283.     {
  284.       if (c == delimiter || delimiter == '\\')
  285.         delimiter = 0;
  286.       continue;
  287.     }
  288.       else
  289.     {
  290.       if (c == '"' || c == '\'' || c == '\\')
  291.         delimiter = c;
  292.     }
  293.     }
  294.  
  295.   l = i - *sindex;
  296.   result = (char *)xmalloc (1 + l);
  297.   strncpy (result, &string[*sindex], l);
  298.   result[l] = '\0';
  299.   *sindex = i;
  300.  
  301.   if (!c && (delimiter || nesting_level))
  302.     {
  303.       report_error ("bad substitution: %s%s", opener, result);
  304.       free (result);
  305.       longjmp (top_level, DISCARD);
  306.     }
  307.   return (result);
  308. }
  309.  
  310. /* An artifact for extracting the contents of a quoted string.  Since the
  311.    string is about to be evaluated, we pass everything through, and only
  312.    strip backslash before backslash or quote. */
  313. /* This is a mini state machine. */
  314. char *
  315. string_extract_double_quoted (string, sindex)
  316.      char *string;
  317.      int *sindex;
  318. {
  319.   register int c, j, i;
  320.   char *temp;            /* The new string we return. */
  321.   int pass_next, backquote;    /* State variables for the machine. */
  322.  
  323.   pass_next = backquote = 0;
  324.   temp = (char *)xmalloc (1 + (strlen (string) - *sindex));
  325.  
  326.   for (j = 0, i = *sindex; c = string[i]; i++)
  327.     {
  328.       /* Process a character that was quoted by a backslash. */
  329.       if (pass_next)
  330.     {
  331.       /* Posix.2 sez:
  332.  
  333.          ``The backslash shall retain its special meaning as an escape
  334.          character only when followed by one of the characters:
  335.              $    `    "    \    <newline>''.
  336.  
  337.          We handle the double quotes here.  expand_word_internal handles
  338.          the rest. */
  339.       if (c != '"')
  340.         temp[j++] = '\\';
  341.           temp[j++] = c;
  342.           pass_next = 0;
  343.           continue;
  344.     }
  345.  
  346.       /* A backslash protects the next character.  The code just above
  347.          handles preserving the backslash in front of any character but
  348.          a double quote. */
  349.       if (c == '\\')
  350.     {
  351.       pass_next++;
  352.       continue;
  353.     }
  354.  
  355.       /* Inside backquotes, ``the portion of the quoted string from the
  356.      initial backquote and the characters up to the next backquote
  357.      that is not preceded by a backslash, having escape characters
  358.      removed, defines that command''. */
  359.       if (backquote)
  360.         {
  361.           if (c == '`')
  362.             backquote = 0;
  363.       temp[j++] = c;
  364.       continue;
  365.         }
  366.  
  367.       if (c == '`')
  368.         {
  369.           temp[j++] = c;
  370.           backquote++;
  371.           continue;
  372.         }
  373.  
  374.       /* Pass everything between `$(' and the matching `)' through verbatim. */
  375.       if (c == '$' && string[i + 1] == '(')
  376.     {
  377.       register int t;
  378.       int si;
  379.       char *ret;
  380.  
  381.       si = i + 2;
  382.       ret = extract_delimited_string (string, &si, "$(", "(", ")");
  383.  
  384.       temp[j++] = '$';
  385.       temp[j++] = '(';
  386.  
  387.       for (t = 0; ret[t]; t++)
  388.         temp[j++] = ret[t];
  389.  
  390.       i = si;
  391.       temp[j++] = string[i];
  392.       free (ret);
  393.       continue;
  394.     }
  395.  
  396.       /* An unescaped double quote serves to terminate the string. */
  397.       if (c == '"')
  398.         break;
  399.  
  400.       /* Add the character to the quoted string we're accumulating. */
  401.       temp[j++] = c;
  402.     }
  403.   temp[j] = '\0';
  404.   *sindex = i;
  405.   return (temp);
  406. }
  407.  
  408. /* Extract the name of the variable to bind to from the assignment string. */
  409. char *
  410. assignment_name (string)
  411.      char *string;
  412. {
  413.   int offset = assignment (string);
  414.   char *temp;
  415.   if (!offset) return (char *)NULL;
  416.   temp = (char *)xmalloc (offset + 1);
  417.   strncpy (temp, string, offset);
  418.   temp[offset] = '\0';
  419.   return (temp);
  420. }
  421.  
  422. /* Return a single string of all the words in LIST.  SEP is the separator
  423.    to put between individual elements of LIST in the output string. */
  424.  
  425. static char *
  426. string_list_internal (list, sep)
  427.      WORD_LIST *list;
  428.      char *sep;
  429. {
  430.   char *result = (char *)NULL;
  431.   int sep_len;
  432.  
  433.   sep_len = strlen (sep);
  434.  
  435.   while (list)
  436.     {
  437.       /* Can't simply let xrealloc malloc the bytes for us the first time
  438.          because of the strcat (result, ...) -- we need to make sure result
  439.          is initialized to null after being allocated initially. */
  440.       if (!result)
  441.     result = savestring ("");
  442.  
  443.       result = (char *)xrealloc
  444.     (result, 2 + sep_len + strlen (result) + strlen (list->word->word));
  445.       strcat (result, list->word->word);
  446.       if (list->next)
  447.     strcat (result, sep);
  448.       list = list->next;
  449.     }
  450.   return (result);
  451. }
  452.  
  453. /* Return a single string of all the words present in LIST, separating
  454.    each word with a space. */
  455. char *
  456. string_list (list)
  457.      WORD_LIST *list;
  458. {
  459.   return (string_list_internal (list, " "));
  460. }
  461.  
  462. /* Return a single string of all the words present in LIST, obeying the
  463.    quoting rules for "$*", to wit: (P1003.2, draft 11, 3.5.2, "If the
  464.    expansion [of $*] appears within a double quoted string, it expands
  465.    to a single field with the value of each parameter separated by the
  466.    first character of the IFS variable, or by a <space> if IFS is unset
  467.    [or null]." */
  468.  
  469. char *
  470. string_list_dollar_star (list)
  471.      WORD_LIST *list;
  472. {
  473.   char *ifs = get_string_value ("IFS");
  474.   char sep[2];
  475.  
  476.   if (!ifs)
  477.     sep[0] = ' ';
  478.   else if (!*ifs)
  479.     sep[0] = '\0';
  480.   else
  481.     sep[0] = *ifs;
  482.  
  483.   sep[1] = '\0';
  484.  
  485.   return (string_list_internal (list, sep));
  486. }
  487.  
  488. /* Return the list of words present in STRING.  Separate the string into
  489.    words at any of the characters found in SEPARATORS.  If QUOTED is
  490.    non-zero then word in the list will have its quoted flag set, otherwise
  491.    the quoted flag is left as make_word () deemed fit.
  492.  
  493.    This obeys the P1003.2 draft 11 word splitting semantics.  If `separators'
  494.    is exactly <space><tab><newline>, then the splitting algorithm is that of
  495.    the Bourne shell, which treats any sequence of characters from `separators'
  496.    as a delimiter.  If IFS is unset, which results in `separators' being set
  497.    to "", no splitting occurs.  If separators has some other value, the
  498.    following rules are applied (`IFS white space' means zero or more
  499.    occurrences of <space>, <tab>, or <newline>, as long as those characters
  500.    are in `separators'):
  501.  
  502.     1) IFS white space is ignored at the start and the end of the
  503.        string.
  504.     2) Each occurrence of a character in `separators' that is not
  505.        IFS white space, along with any adjacent occurrences of
  506.        IFS white space delimits a field.
  507.     3) Any nonzero-length sequence of IFS white space delimits a field.
  508.    */
  509.  
  510. /* BEWARE!  list_string strips null arguments.  Don't call it twice and
  511.    expect to have "" preserved! */
  512.  
  513. /* Is C a quoted NULL character? */
  514. #define QUOTED_NULL(c) ((unsigned char)(c) == (unsigned char)0x80)
  515.  
  516. /* Perform quoted null character removal on STRING. */
  517. void
  518. remove_quoted_nulls (string)
  519.      char *string;
  520. {
  521.   register char *s;
  522.  
  523.   for (s = string; s && *s; s++)
  524.     {
  525.       if (QUOTED_NULL (*s))
  526.     {
  527.       strcpy (s, s + 1);
  528.       s--;
  529.     }
  530.     }
  531. }
  532.  
  533. /* Perform quoted null character removal on each element of LIST.
  534.    This modifies LIST. */
  535. word_list_remove_quoted_nulls (list)
  536.      WORD_LIST *list;
  537. {
  538.   register WORD_LIST *t;
  539.  
  540.   t = list;
  541.  
  542.   while (t)
  543.     {
  544.       remove_quoted_nulls (t->word->word);
  545.       t = t->next;
  546.     }
  547. }
  548.  
  549. /* This performs word splitting and quoted null character removal on
  550.    STRING. */
  551.  
  552. #define issep(c)    (member ((c), separators))
  553. #define spctabnl(c)    ((c) == ' '|| (c) == '\t' || (c) == '\n')
  554.  
  555. WORD_LIST *
  556. list_string (string, separators, quoted)
  557.      register char *string, *separators;
  558.      int quoted;
  559. {
  560.   WORD_LIST *result = (WORD_LIST *)NULL;
  561.   char *current_word = (char *)NULL, *s;
  562.   int sindex = 0;
  563.   int sh_style_split;
  564.  
  565.   if (!string || !*string)
  566.     return ((WORD_LIST *)NULL);
  567.  
  568.   sh_style_split = separators && *separators && (!strcmp (separators, " \t\n"));
  569.  
  570.   /* Remove sequences of whitespace at the beginning and end of STRING, as
  571.      long as those characters appear in IFS. */
  572.   for (s = string; *s && spctabnl (*s) && issep (*s); s++);
  573.   if (!*s)
  574.     return ((WORD_LIST *)NULL);
  575.   string = s;
  576.   s += strlen (s) - 1;
  577.   for ( ; s > string && *s && spctabnl (*s) & issep (*s); s--);
  578.   if (!*s)
  579.     return ((WORD_LIST *)NULL);
  580.   *++s = '\0';
  581.  
  582.   /* OK, now STRING points to a word that does not begin with white space.
  583.      The splitting algorithm is:
  584.          extract a word, stopping at a separator
  585.          skip sequences of spc, tab, or nl as long as they are separators
  586.      This obeys the field splitting rules in Posix.2 draft 11.x. */
  587.  
  588.   while (string[sindex])
  589.     {
  590.       current_word = string_extract_verbatim (string, &sindex, separators);
  591.       if (!current_word)
  592.         break;
  593.  
  594.       /* If we have a quoted empty string, add a quoted null argument.  We
  595.      want to preserve the quoted null character iff this is a quoted
  596.      empty string; otherwise the quoted null characters are removed
  597.      below. */
  598.       if (QUOTED_NULL (current_word[0]) && current_word[1] == '\0')
  599.     {
  600.       WORD_DESC *t = make_word (" ");
  601.       t->quoted++;
  602.       t->word[0] = (unsigned char)QUOTE_CHAR ('\0');
  603.       result = make_word_list (t, result);
  604.     }
  605.  
  606.       /* If we have something, then add it regardless. */
  607.       else if (strlen (current_word))
  608.     {
  609.       register char *temp_string;
  610.  
  611.       /* Perform quoted null character removal on the current word. */
  612.        for (temp_string = current_word; *temp_string; temp_string++)
  613.         if (QUOTED_NULL (*temp_string))
  614.           {
  615.         strcpy (temp_string, temp_string + 1);
  616.         temp_string--;
  617.           }
  618.  
  619.       result = make_word_list (make_word (current_word), result);
  620.       if (quoted)
  621.         result->word->quoted++;
  622.     }
  623.  
  624.       /* If we're not doing sequences of separators in the traditional
  625.      Bourne shell style, then add a quoted null argument. */
  626.  
  627.       else if (!sh_style_split && !spctabnl (string[sindex]))
  628.     {
  629.       result = make_word_list (make_word (""), result);
  630.       result->word->quoted++;
  631.     }
  632.  
  633.       free (current_word);
  634.  
  635.       /* Move past the current separator character. */
  636.       if (string[sindex])
  637.         sindex++;
  638.  
  639.       /* Now skip sequences of space, tab, or newline characters if they are
  640.          in the list of separators. */
  641.       while (string[sindex] &&
  642.          spctabnl (string[sindex]) &&
  643.          issep (string[sindex]))
  644.     sindex++;
  645.  
  646.     }
  647.   return (WORD_LIST *)reverse_list (result);
  648. }
  649.  
  650. /* Given STRING, an assignment string, get the value of the right side
  651.    of the `=', and bind it to the left side.  If EXPAND is true, then
  652.    perform parameter expansion, command substitution, and arithmetic
  653.    expansion on the right-hand side.  Perform tilde expansion in any
  654.    case.  Do not perform word splitting on the result of expansion. */
  655. do_assignment_internal (string, expand)
  656.      char *string;
  657.      int expand;
  658. {
  659.   int offset = assignment (string);
  660.   char *name = savestring (string);
  661.   char *value = (char *)NULL;
  662.   SHELL_VAR *entry = (SHELL_VAR *)NULL;
  663.  
  664.   if (name[offset] == '=')
  665.     {
  666.       char *tilde_expand (), *string_list ();
  667.       WORD_LIST *list, *expand_string_unsplit ();
  668.       char *temp;
  669.  
  670.       name[offset] = 0;
  671.       temp = name + offset + 1;
  672.  
  673.       if (expand)
  674.     {
  675.       if (index (temp, '~'))
  676.         temp = tilde_expand (temp);
  677.       else
  678.         temp = savestring (temp);
  679.  
  680.       list = expand_string_unsplit (temp, 0);
  681.  
  682.       if (list)
  683.         {
  684.           value = string_list (list);
  685.           dispose_words (list);
  686.         }
  687.       free (temp);
  688.     }
  689.       else
  690.     value = savestring (temp);
  691.     }
  692.  
  693.   if (!value)
  694.     value = savestring ("");
  695.  
  696.   entry = bind_variable (name, value);
  697.  
  698.   if (echo_command_at_execute)
  699.     {
  700.       extern char *indirection_level_string ();
  701.       fprintf (stderr, "%s%s=%s\n", indirection_level_string (), name, value);
  702.     }
  703.  
  704.   /* Yes, here is where the special shell variables get tested for.
  705.      Don't ask me, I just work here.  This is really stupid.  I would
  706.      swear, but I've decided that that is an impolite thing to do in
  707.      source that is to be distributed around the net, even if this code
  708.      is totally brain-damaged. */
  709.  
  710.   /* if (strcmp (name, "PATH") == 0) Yeeecchhh!!!*/
  711.   stupidly_hack_special_variables (name);
  712.  
  713.   if (entry)
  714.     entry->attributes &= ~att_invisible;
  715.   if (value)
  716.     free (value);
  717.   free (name);
  718. }
  719.  
  720. /* Perform the assignment statement in STRING, and expand the
  721.    right side by doing command and parameter expansion. */
  722. do_assignment (string)
  723.      char *string;
  724. {
  725.   do_assignment_internal (string, 1);
  726. }
  727.  
  728. /* Given STRING, an assignment string, get the value of the right side
  729.    of the `=', and bind it to the left side.  Do not do command and
  730.    parameter substitution on the right hand side. */
  731. do_assignment_no_expand (string)
  732.      char *string;
  733. {
  734.   do_assignment_internal (string, 0);
  735. }
  736.  
  737. /* Most of the substitutions must be done in parallel.  In order
  738.    to avoid using tons of unclear goto's, I have some functions
  739.    for manipulating malloc'ed strings.  They all take INDEX, a
  740.    pointer to an integer which is the offset into the string
  741.    where manipulation is taking place.  They also take SIZE, a
  742.    pointer to an integer which is the current length of the
  743.    character array for this string. */
  744.  
  745. /* Append SOURCE to TARGET at INDEX.  SIZE is the current amount
  746.    of space allocated to TARGET.  SOURCE can be NULL, in which
  747.    case nothing happens.  Gets rid of SOURCE by free ()ing it.
  748.    Returns TARGET in case the location has changed. */
  749. char *
  750. sub_append_string (source, target, index, size)
  751.      char *source, *target;
  752.      int *index, *size;
  753. {
  754.   if (source)
  755.     {
  756.       while ((int)strlen (source) >= (int)(*size - *index))
  757.     target = (char *)xrealloc (target, *size += DEFAULT_ARRAY_SIZE);
  758.  
  759.       strcat (target, source);
  760.       *index += strlen (source);
  761.  
  762.       free (source);
  763.     }
  764.   return (target);
  765. }
  766.  
  767. /* Append the textual representation of NUMBER to TARGET.
  768.    INDEX and SIZE are as in SUB_APPEND_STRING. */
  769. char *
  770. sub_append_number (number, target, index, size)
  771.      int number, *index, *size;
  772.      char *target;
  773. {
  774.   char *temp = (char *)xmalloc (10);
  775.   sprintf (temp, "%d", number);
  776.   return (sub_append_string (temp, target, index, size));
  777. }
  778.  
  779. /* Return the word list that corresponds to `$*'. */
  780. WORD_LIST *
  781. list_rest_of_args ()
  782. {
  783.   register WORD_LIST *list = (WORD_LIST *)NULL;
  784.   register WORD_LIST *args = rest_of_args;
  785.   int i;
  786.  
  787.   for (i = 1; i < 10; i++)
  788.     if (dollar_vars[i])
  789.       list = make_word_list (make_word (dollar_vars[i]), list);
  790.   while (args)
  791.     {
  792.       list = make_word_list (make_word (args->word->word), list);
  793.       args = args->next;
  794.     }
  795.   return ((WORD_LIST *)reverse_list (list));
  796. }
  797.  
  798. /* Make a single large string out of the dollar digit variables,
  799.    and the rest_of_args.  If DOLLAR_STAR is 1, then obey the special
  800.    case of "$*" with respect to IFS. */
  801. char *
  802. string_rest_of_args (dollar_star)
  803.      int dollar_star;
  804. {
  805.   register WORD_LIST *list = list_rest_of_args ();
  806.   char *string;
  807.  
  808.   if (!dollar_star)
  809.     string = string_list (list);
  810.   else
  811.     string = string_list_dollar_star (list);
  812.  
  813.   dispose_words (list);
  814.   return (string);
  815. }
  816.  
  817. /***************************************************
  818.  *                           *
  819.  *       Functions to Expand a String           *
  820.  *                           *
  821.  ***************************************************/
  822.  
  823. /* Perform parameter expansion, command substitution, and arithmetic
  824.    expansion on STRING, as if it were a word.  Leave the result quoted. */
  825. static WORD_LIST *
  826. expand_string_internal (string, quoted)
  827.      char *string;
  828.      int quoted;
  829. {
  830.   WORD_DESC *make_word (), *temp = make_word (string);
  831.   WORD_LIST *tresult, *expand_word_internal ();
  832.  
  833.   tresult  = expand_word_internal (temp, quoted, (int *)NULL, (int *)NULL);
  834.   dispose_word (temp);
  835.   return (tresult);
  836. }
  837.  
  838. /* Expand STRING by performing parameter expansion, command substitution,
  839.    and arithmetic expansion.  Dequote the resulting WORD_LIST before
  840.    returning it, but do not perform word splitting.  The call to
  841.    remove_quoted_nulls () is in here because word splitting normally
  842.    takes care of quote removal. */
  843. WORD_LIST *
  844. expand_string_unsplit (string, quoted)
  845.      char *string;
  846.      int quoted;
  847. {
  848.   WORD_LIST *value = expand_string_internal (string, quoted);
  849.  
  850.   if (value && value->word)
  851.     remove_quoted_nulls (value->word->word);
  852.  
  853.   if (value)
  854.     dequote_list (value);
  855.   return (value);
  856. }
  857.  
  858. /* Expand STRING just as if you were expanding a word.  This also returns
  859.    a list of words.  Note that filename globbing is *NOT* done for word
  860.    or string expansion, just when the shell is expanding a command.  This
  861.    does parameter expansion, command substitution, arithmetic expansion,
  862.    and word splitting.  Dequote the resultant WORD_LIST before returning. */
  863. WORD_LIST *
  864. expand_string (string, quoted)
  865.      char *string;
  866.      int quoted;
  867. {
  868.   WORD_LIST *value = expand_string_internal (string, quoted);
  869.   WORD_LIST *result, *word_list_split ();
  870.  
  871.   result = word_list_split (value);
  872.   dispose_words (value);
  873.   if (result)
  874.     dequote_list (result);
  875.   return (result);
  876. }
  877.  
  878. /* Expand STRING just as if you were expanding a word, but do not dequote
  879.    the resultant WORD_LIST.  This is called only from within this file,
  880.    and is used to correctly preserve quoted characters when expanding
  881.    things like ${1+"$@"}.  This does parameter expansion, command
  882.    subsitution, arithmetic expansion, and word splitting. */
  883. static WORD_LIST *
  884. expand_string_leave_quoted (string, quoted)
  885.      char *string;
  886.      int quoted;
  887. {
  888.   WORD_LIST *tlist  = expand_string_internal (string, quoted);
  889.   WORD_LIST *tresult, *word_list_split ();
  890.  
  891.   tresult = word_list_split (tlist);
  892.   dispose_words (tlist);
  893.   return (tresult);
  894. }
  895.  
  896. /***************************************************
  897.  *                           *
  898.  *    Functions to handle quoting chars       *
  899.  *                           *
  900.  ***************************************************/
  901.  
  902. /* I'm going to have to rewrite expansion because filename globbing is
  903.    beginning to make the entire arrangement ugly.  I'll do this soon. */
  904. dequote_list (list)
  905.      register WORD_LIST *list;
  906. {
  907.   register char *s;
  908.  
  909.   while (list)
  910.     {
  911.       s = dequote_string (list->word->word);
  912.       free (list->word->word);
  913.       list->word->word = s;
  914.       list = list->next;
  915.     }
  916. }
  917.  
  918. /* Quote the string S.  Return a new string. */
  919. static char *
  920. quote_string (s)
  921.      char *s;
  922. {
  923.   unsigned char *result;
  924.  
  925.   /* If S is an empty string then simply create a string consisting of a
  926.      quoted null. */
  927.   if (s[0] == '\0')
  928.     {
  929.       result = (unsigned char *)xmalloc (2);
  930.       result[0] = (unsigned char)QUOTE_CHAR ('\0');
  931.       result[1] = '\0';
  932.     }
  933.   else
  934.     {
  935.       register unsigned char *t;
  936.       result = (unsigned char *)savestring (s);
  937.       for (t = result; t && *t ; t++)
  938.     *t |= 0x80;
  939.     }
  940.   return ((char *)result);
  941. }
  942.  
  943. /* De-quoted quoted characters in string s. */
  944. static char *
  945. dequote_string (s)
  946.      char *s;
  947. {
  948.   register unsigned char *t;
  949.   unsigned char *result;
  950.  
  951.   result = (unsigned char *)savestring (s);
  952.   for (t = result; t && *t ; t++)
  953.     *t = DEQUOTE_CHAR (*t);
  954.  
  955.   return ((char *)result);
  956. }
  957.  
  958. /* Quote the entire WORD_LIST list. */
  959. static void
  960. quote_list (list)
  961.      WORD_LIST *list;
  962. {
  963.   register WORD_LIST *w;
  964.  
  965.   for (w = list; w; w = w->next)
  966.     {
  967.       char *t = w->word->word;
  968.       w->word->word = quote_string (t);
  969.       free (t);
  970.       w->word->quoted = 1;
  971.     }
  972. }
  973.  
  974. /* **************************************************************** */
  975. /*                                    */
  976. /*            Functions for Removing Patterns            */
  977. /*                                    */
  978. /* **************************************************************** */
  979.  
  980. /* Remove the portion of PARAM matched by PATTERN according to OP, where OP
  981.    can have one of 4 values:
  982.     RP_LONG_LEFT    remove longest matching portion at start of PARAM
  983.     RP_SHORT_LEFT    remove shortest matching portion at start of PARAM
  984.     RP_LONG_RIGHT    remove longest matching portion at end of PARAM
  985.     RP_SHORT_RIGHT    remove shortest matching portion at end of PARAM
  986. */
  987.  
  988. #define RP_LONG_LEFT    1
  989. #define RP_SHORT_LEFT    2
  990. #define RP_LONG_RIGHT    3
  991. #define RP_SHORT_RIGHT    4
  992.  
  993. static char *
  994. remove_pattern (param, pattern, op)
  995.      char *param, *pattern;
  996.      int op;
  997. {
  998.   register int len = param ? strlen (param) : 0;
  999.   register char *end = param + len;
  1000.   register char *p, *ret, c;
  1001.  
  1002.   if (pattern == NULL || *pattern == '\0')    /* minor optimization */
  1003.     return (savestring (param));
  1004.  
  1005.   if (param == NULL || *param == '\0')
  1006.     return (param);
  1007.  
  1008.   switch (op)
  1009.     {
  1010.       case RP_LONG_LEFT:    /* remove longest match at start */
  1011.     for (p = end; p >= param; p--)
  1012.       {
  1013.         c = *p; *p = '\0';
  1014.         if (fnmatch (pattern, param, 0) != FNM_NOMATCH)
  1015.           {
  1016.         *p = c;
  1017.         return (savestring (p));
  1018.           }
  1019.         *p = c;
  1020.       }
  1021.     break;
  1022.  
  1023.       case RP_SHORT_LEFT:    /* remove shortest match at start */
  1024.     for (p = param; p <= end; p++)
  1025.       {
  1026.         c = *p; *p = '\0';
  1027.         if (fnmatch (pattern, param, 0) != FNM_NOMATCH)
  1028.           {
  1029.         *p = c;
  1030.         return (savestring (p));
  1031.           }
  1032.         *p = c;
  1033.       }
  1034.     break;
  1035.  
  1036.       case RP_LONG_RIGHT:    /* remove longest match at end */
  1037.     for (p = param; p <= end; p++)
  1038.       {
  1039.         if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
  1040.           {
  1041.         c = *p;
  1042.         *p = '\0';
  1043.         ret = savestring (param);
  1044.         *p = c;
  1045.         return (ret);
  1046.           }
  1047.       }
  1048.     break;
  1049.  
  1050.       case RP_SHORT_RIGHT:    /* remove shortest match at end */
  1051.     for (p = end; p >= param; p--)
  1052.       {
  1053.         if (fnmatch (pattern, p, 0) != FNM_NOMATCH)
  1054.           {
  1055.         c = *p;
  1056.         *p = '\0';
  1057.         ret = savestring (param);
  1058.         *p = c;
  1059.         return (ret);
  1060.           }
  1061.       }
  1062.     break;
  1063.     }
  1064.   return (savestring (param));    /* no match, return original string */
  1065. }
  1066.  
  1067. /*******************************************
  1068.  *                       *
  1069.  *    Functions to expand WORD_DESCs       *
  1070.  *                       *
  1071.  *******************************************/
  1072.  
  1073. /* Expand WORD, performing word splitting on the result.  This does
  1074.    parameter expansion, command substitution, arithmetic expansion,
  1075.    word splitting, and quote removal. */
  1076.  
  1077. WORD_LIST *
  1078. expand_word (word, quoted)
  1079.      WORD_DESC *word;
  1080.      int quoted;
  1081. {
  1082.   WORD_LIST *word_list_split (), *expand_word_internal ();
  1083.   WORD_LIST *result, *tresult;
  1084.  
  1085.   tresult = expand_word_internal (word, quoted, (int *)NULL, (int *)NULL);
  1086.   result = word_list_split (tresult);
  1087.   dispose_words (tresult);
  1088.   if (result)
  1089.     dequote_list (result);
  1090.   return (result);
  1091. }
  1092.  
  1093. /* Expand WORD, but do not perform word splitting on the result.  This
  1094.    does parameter expansion, command substitution, arithmetic expansion,
  1095.    and quote removal. */
  1096. WORD_LIST *
  1097. expand_word_no_split (word, quoted)
  1098.      WORD_DESC *word;
  1099.      int quoted;
  1100. {
  1101.   WORD_LIST *expand_word_internal ();
  1102.   WORD_LIST *result;
  1103.  
  1104.   result = expand_word_internal (word, quoted, (int *)NULL, (int *)NULL);
  1105.   if (result)
  1106.     dequote_list (result);
  1107.   return (result);
  1108. }
  1109.  
  1110. WORD_LIST *
  1111. expand_word_leave_quoted (word, quoted)
  1112.      WORD_DESC *word;
  1113.      int quoted;
  1114. {
  1115.   WORD_LIST *expand_word_internal (), *result;
  1116.  
  1117.   result = expand_word_internal (word, quoted, (int *)NULL, (int *)NULL);
  1118.   return (result);
  1119. }
  1120.  
  1121. /* Return the value of a positional parameter.  This handles values > 10. */
  1122. char *
  1123. get_dollar_var_value (ind)
  1124.      int ind;
  1125. {
  1126.   char *temp;
  1127.  
  1128.   if (ind < 10)
  1129.     {
  1130.       if (dollar_vars[ind])
  1131.     temp = savestring (dollar_vars[ind]);
  1132.       else
  1133.     temp = (char *)NULL;
  1134.     }
  1135.   else    /* We want something like ${11} */
  1136.     {
  1137.       WORD_LIST *p = rest_of_args;
  1138.  
  1139.       ind -= 10;
  1140.       while (p && ind--)
  1141.     p = p->next;
  1142.       if (p)
  1143.     temp = savestring (p->word->word);
  1144.       else
  1145.     temp = (char *)NULL;
  1146.     }
  1147.   return (temp);
  1148. }
  1149.  
  1150. /* Perform command substitution on STRING.  This returns a string,
  1151.    possibly quoted. */
  1152. static char *
  1153. command_substitute (string, quoted)
  1154.      char *string;
  1155.      int quoted;
  1156. {
  1157.   pid_t pid, old_pid;
  1158.   int fildes[2];
  1159.   char *istring = (char *)NULL;
  1160.   int istring_index, istring_size, c = 1;
  1161.   extern int interactive, last_command_exit_value;
  1162.  
  1163.   istring_index = istring_size = 0;
  1164.  
  1165.   /* Don't fork () if there is no need to.  In the case of no command to
  1166.      run, just return NULL. */
  1167.   if (!string || !*string)
  1168.     return ((char *)NULL);
  1169.  
  1170.   /* Pipe the output of executing STRING into the current shell. */
  1171.   if (pipe (fildes) < 0)
  1172.     {
  1173.       report_error ("Can't make pipes for command substitution!");
  1174.       goto error_exit;
  1175.     }
  1176.       
  1177.   old_pid = last_made_pid;
  1178. #if defined (JOB_CONTROL)
  1179.   {
  1180.     pid_t old_pipeline_pgrp = pipeline_pgrp;    
  1181.  
  1182.     pipeline_pgrp = shell_pgrp;
  1183.     pid = make_child (savestring ("command substitution"), 0);
  1184.  
  1185.     stop_making_children ();
  1186.     pipeline_pgrp = old_pipeline_pgrp;
  1187.   }
  1188. #else   /* JOB_CONTROL */
  1189.   pid = make_child (savestring ("command substitution"), 0);
  1190. #endif  /* JOB_CONTROL */
  1191.  
  1192.   if (pid < 0)
  1193.     {
  1194.       report_error ("Can't make a child for command substitution!");
  1195.     error_exit:
  1196.       if (istring)
  1197.     free (istring);
  1198.       return ((char *)NULL);
  1199.     }
  1200.  
  1201.   if (pid == 0)
  1202.     {
  1203. #if defined (JOB_CONTROL)
  1204.       set_job_control (0);
  1205. #endif
  1206.       if (dup2 (fildes[1], 1) < 0)
  1207.     {
  1208.       extern int errno;
  1209.       report_error ("command_substitute: cannot duplicate pipe as fd 1: %s\n",
  1210.             strerror (errno));
  1211.       exit (EXECUTION_FAILURE);
  1212.     }
  1213.       close (fildes[1]);
  1214.       /* If standard output is closed in the parent shell
  1215.      (such as after `exec >&-'), file descriptor 1 will be
  1216.      the lowest available file descriptor, and end up in
  1217.      fildes[0].  This can happen for stdin and stderr as well,
  1218.      but stdout is more important -- it will cause no output
  1219.      to be generated from this command. */
  1220.       if (fildes[0] > 2)
  1221.     close (fildes[0]);
  1222.       interactive = 0;
  1223.  
  1224.       exit (parse_and_execute (string, "command substitution"));
  1225.     }
  1226.   else
  1227.     {
  1228.       FILE *istream;
  1229.  
  1230.       istream = fdopen (fildes[0], "r");
  1231.  
  1232. #if defined (JOB_CONTROL) && defined (PGRP_PIPE)
  1233.       close_pgrp_pipe ();
  1234. #endif /* JOB_CONTROL && PGRP_PIPE */
  1235.  
  1236.       close (fildes[1]);
  1237.  
  1238.       if (!istream)
  1239.     {
  1240.       report_error ("Can't reopen pipe to command substitution");
  1241.       goto error_exit;
  1242.     }
  1243.  
  1244.       /* Read the output of the command through the pipe. */
  1245.       while (1)
  1246.     {
  1247. #if defined (USG) || (defined (_POSIX_VERSION) && defined (Ultrix))
  1248.       c = sysv_getc (istream);
  1249. #else
  1250.       c = getc (istream);
  1251. #endif
  1252.  
  1253.       if (c == EOF)
  1254.         break;
  1255.  
  1256.       /* Add the character to ISTRING. */
  1257.       while (istring_index + 1 >= istring_size)
  1258.         istring = (char *) xrealloc
  1259.           (istring, istring_size += DEFAULT_ARRAY_SIZE);
  1260.  
  1261.       if (quoted)
  1262.         istring[istring_index++] = QUOTE_CHAR (c);
  1263.       else
  1264.         istring[istring_index++] = c;
  1265.  
  1266.       istring[istring_index] = '\0';
  1267.     }
  1268.  
  1269.       fclose (istream);
  1270.       close (fildes[0]);
  1271.  
  1272.       last_command_exit_value = wait_for (pid);
  1273.       last_command_subst_pid = pid;
  1274.       last_made_pid = old_pid;
  1275.  
  1276. #if defined (JOB_CONTROL)
  1277.       /* If last_command_exit_value > 128, then the substituted command
  1278.      was terminated by a signal.  If that signal was SIGINT, then send
  1279.      SIGINT to ourselves.  This will break out of loops, for instance. */
  1280.       if (last_command_exit_value == (128 + SIGINT))
  1281.     kill (getpid (), SIGINT);
  1282.  
  1283.       /* wait_for gives the terminal back to shell_pgrp.  If some other
  1284.          process group should have it, give it away to that group here. */
  1285.       if (pipeline_pgrp != (pid_t)0)
  1286.     give_terminal_to (pipeline_pgrp);
  1287. #endif /* JOB_CONTROL */
  1288.  
  1289.       /* If we read no output, just return now and save ourselves some
  1290.      trouble. */
  1291.       if (istring_index == 0)
  1292.     goto error_exit;
  1293.  
  1294.       /* Strip trailing newlines from the output of the command. */
  1295.       if (quoted)
  1296.     {
  1297.       while (istring_index > 0 &&
  1298.           DEQUOTE_CHAR (istring[istring_index - 1]) == '\n')
  1299.         --istring_index;
  1300.  
  1301.       istring[istring_index] = '\0';
  1302.     }
  1303.       else
  1304.     {
  1305.       strip_trailing (istring, 1);
  1306.       istring_index = strlen (istring);
  1307.     }
  1308.  
  1309.       return (istring);
  1310.     }
  1311. }
  1312.  
  1313. /********************************************************
  1314.  *                            *
  1315.  *    Utility functions for parameter expansion    *
  1316.  *                            *
  1317.  ********************************************************/
  1318.  
  1319. /* Handle removing a pattern from a string as a result of ${name%[%]value}
  1320.    or ${name#[#]value}. */
  1321. static char *
  1322. parameter_brace_remove_pattern (value, temp, c)
  1323.      char *value, *temp;
  1324.      int c;
  1325. {
  1326.   int pattern_specifier;
  1327.   WORD_LIST *l;
  1328.   char *pattern, *t;
  1329.  
  1330.   if (c == '#')
  1331.     {
  1332.       if (*value == '#')
  1333.     {
  1334.       value++;
  1335.       pattern_specifier = RP_LONG_LEFT;
  1336.     }
  1337.       else
  1338.     pattern_specifier = RP_SHORT_LEFT;
  1339.     }
  1340.   else    /* c == '%' */
  1341.     {
  1342.       if (*value == '%')
  1343.     {
  1344.       value++;
  1345.       pattern_specifier = RP_LONG_RIGHT;
  1346.     }
  1347.       else
  1348.     pattern_specifier = RP_SHORT_RIGHT;
  1349.     }
  1350.  
  1351.   l = expand_string (value, 0);
  1352.   pattern = (char *)string_list (l);
  1353.   dispose_words (l);
  1354.   t = remove_pattern (temp, pattern, pattern_specifier);
  1355.   free (pattern);
  1356.   return (t);
  1357. }
  1358.  
  1359. /* Parameter expand NAME, and return a new string which is the expansion,
  1360.    or NULL if there was no expansion.
  1361.    VAR_IS_SPECIAL is non-zero if NAME is one of the special variables in
  1362.    the shell, e.g., "@", "$", "*", etc.  QUOTED, if non-zero, means that
  1363.    NAME was found inside of a double-quoted expression. */
  1364. static char *
  1365. parameter_brace_expand_word (name, var_is_special, quoted)
  1366.      char *name;
  1367.      int var_is_special, quoted;
  1368. {
  1369.   char *temp = (char *)NULL;
  1370.  
  1371.   /* Handle multiple digit arguments, as in ${11}. */
  1372.   if (digit (*name))
  1373.     {
  1374.       int arg_index = atoi (name);
  1375.  
  1376.       temp = get_dollar_var_value (arg_index);
  1377.     }
  1378.   else if (var_is_special)      /* ${@} */
  1379.     {
  1380.       char *tt;
  1381.       WORD_LIST *l;
  1382.  
  1383.       tt = (char *)alloca (2 + strlen (name));
  1384.       tt[0] = '$'; tt[1] = '\0';
  1385.       strcat (tt, name);
  1386.       l = expand_string_leave_quoted (tt, quoted);
  1387.       temp = string_list (l);
  1388.       dispose_words (l);
  1389.     }
  1390.   else
  1391.     {
  1392.       SHELL_VAR *var = find_variable (name);
  1393.  
  1394.       if (var && !invisible_p (var) && (temp = value_cell (var)))
  1395.     temp = savestring (temp);
  1396.     }
  1397.   return (temp);
  1398. }
  1399.  
  1400. /* Expand the right side of a parameter expansion of the form ${NAMEcVALUE},
  1401.    depending on the value of C, the separating character.  C can be one of
  1402.    "-", "+", or "=". */
  1403. static char *
  1404. parameter_brace_expand_rhs (name, value, c, quoted)
  1405.      char *name, *value;
  1406.      int c;
  1407. {
  1408.   extern char *tilde_expand ();
  1409.   WORD_LIST *l;
  1410.   char *t, *t1, *temp;
  1411.  
  1412.   if (value[0] == '~' ||
  1413.       (index (value, '~') && unquoted_substring ("=~", value)))
  1414.     temp = tilde_expand (value);
  1415.   else
  1416.     temp = savestring (value);
  1417.  
  1418.   l = expand_string_leave_quoted (temp, quoted);
  1419.   free (temp);
  1420.  
  1421.   temp = (char *)string_list (l);
  1422.   dispose_words (l);
  1423.  
  1424.   if (c == '-' || c == '+')
  1425.     return (temp);
  1426.  
  1427.   /* c == '=' */
  1428.   if (temp)
  1429.     t = savestring (temp);
  1430.   else
  1431.     t = savestring ("");
  1432.   t1 = dequote_string (t);
  1433.   free (t);
  1434.   t = t1;
  1435.   bind_variable (name, t);
  1436.   free (t);
  1437.   return (temp);
  1438. }
  1439.  
  1440. /* Deal with the right hand side of a ${name:?value} expansion in the case
  1441.    that NAME is null or not set.  If VALUE is non-null it is expanded and
  1442.    used as the error message to print, otherwise a standard message is
  1443.    printed. */
  1444. static void
  1445. parameter_brace_expand_error (name, value)
  1446.      char *name, *value;
  1447. {
  1448.   extern int interactive;
  1449.  
  1450.   if (value && *value)
  1451.     {
  1452.       WORD_LIST *l = expand_string (value, 0);
  1453.       char *temp1 =  string_list (l);
  1454.       fprintf (stderr, "%s: %s\n", name, temp1 ? temp1 : value);
  1455.       if (temp1)
  1456.     free (temp1);
  1457.       dispose_words (l);
  1458.     }
  1459.   else
  1460.     report_error ("%s: parameter null or not set", name);
  1461.  
  1462.   /* Free the data we have allocated during this expansion, since we
  1463.      are about to longjmp out. */
  1464.   free (name);
  1465.   if (value)
  1466.     free (value);
  1467.  
  1468.   if (!interactive)
  1469.     longjmp (top_level, FORCE_EOF);
  1470.   else
  1471.     longjmp (top_level, DISCARD);
  1472. }
  1473.  
  1474. /* Handle the parameter brace expansion that requires us to return the
  1475.    length of a parameter. */
  1476. static int
  1477. parameter_brace_expand_length (name)
  1478.      char *name;
  1479. {
  1480.   char *t;
  1481.   int number = 0;
  1482.  
  1483.   if (name[1] == '\0')            /* ${#} */
  1484.     {
  1485.       WORD_LIST *l = list_rest_of_args ();
  1486.       number = list_length (l);
  1487.       dispose_words (l);
  1488.     }
  1489.   else if (name[1] != '*' && name[1] != '@')
  1490.     {
  1491.       number = 0;
  1492.  
  1493.       if (digit (name[1]))        /* ${#1} */
  1494.     {
  1495.       if (t = get_dollar_var_value (atoi (&name[1])))
  1496.         {
  1497.           number = strlen (t);
  1498.           free (t);
  1499.         }
  1500.     }
  1501.       else                /* ${#PS1} */
  1502.     {
  1503.       WORD_LIST *list;
  1504.       char *newname;
  1505.  
  1506.       newname = savestring (name);
  1507.       newname[0] = '$';
  1508.       list = expand_string (newname, 0);
  1509.       t = string_list (list);
  1510.       free (newname);
  1511.       dispose_words (list);
  1512.  
  1513.       if (t)
  1514.         number = strlen (t);
  1515.     }
  1516.     }
  1517.   else                    /* ${#@} and ${#*} */
  1518.     {
  1519.       if (t = string_rest_of_args (1))
  1520.     {
  1521.       number = strlen (t);
  1522.       free (t);
  1523.     }
  1524.     }
  1525.   return (number);
  1526. }
  1527.  
  1528. /* Make a word list which is the parameter and variable expansion,
  1529.    command substitution, arithmetic substitution, and quote removed
  1530.    expansion of WORD.  Return a pointer to a WORD_LIST which is the
  1531.    result of the expansion.  If WORD contains a null word, the word
  1532.    list returned is also null.
  1533.  
  1534.    QUOTED, when non-zero specifies that the text of WORD is treated
  1535.    as if it were surrounded by double quotes.
  1536.    CONTAINS_DOLLAR_AT and EXPANDED_SOMETHING are return values; when non-null
  1537.    they point to an integer value which receives information about expansion.
  1538.    CONTAINS_DOLLAR_AT gets non-zero if WORD contained "$@", else zero.
  1539.    EXPANDED_SOMETHING get non-zero if WORD contained any parameter expansions,
  1540.    else zero.
  1541.  
  1542.    This only does word splitting in the case of $@ expansion.  In that
  1543.    case, we split on ' '. */
  1544. WORD_LIST *
  1545. expand_word_internal (word, quoted, contains_dollar_at, expanded_something)
  1546.      WORD_DESC *word;
  1547.      int quoted;
  1548.      int *contains_dollar_at;
  1549.      int *expanded_something;
  1550. {
  1551.   extern char *itos ();
  1552.   extern int last_command_exit_value;
  1553.  
  1554.   /* The thing that we finally output. */
  1555.   WORD_LIST *result = (WORD_LIST *)NULL;
  1556.  
  1557.   /* The intermediate string that we build while expanding. */
  1558.   char *istring = (char *)xmalloc (DEFAULT_ARRAY_SIZE);
  1559.  
  1560.   /* The current size of the above object. */
  1561.   int istring_size = DEFAULT_ARRAY_SIZE;
  1562.  
  1563.   /* Index into ISTRING. */
  1564.   int istring_index = 0;
  1565.  
  1566.   /* Temporary string storage. */
  1567.   char *temp = (char *)NULL;
  1568.  
  1569.   /* The text of WORD. */
  1570.   register char *string = word->word;
  1571.  
  1572.   /* The index into STRING. */
  1573.   register int sindex = 0;
  1574.  
  1575.   /* This gets 1 if we see a $@ while quoted. */
  1576.   int quoted_dollar_at = 0;
  1577.  
  1578.   /* This gets 1 if we are to treat backslashes as if we are within double
  1579.      quotes, but not otherwise behave as if the word is quoted.  This is
  1580.      used for things like expansion of patterns in case statement pattern
  1581.      lists.  This is a private variable, but the incoming value of
  1582.      Q_KEEP_BACKSLASH is passed to recursive invocations of this function. */
  1583.   int preserve_backslashes = 0;
  1584.  
  1585.   register int c;        /* Current character. */
  1586.   int number;            /* Temporary number value. */
  1587.   int t_index;            /* For calls to string_extract_xxx. */
  1588.   extern int interactive;
  1589.   char *command_subst_result;    /* For calls to command_substitute (). */
  1590.  
  1591.   istring[0] = '\0';
  1592.  
  1593.   if (!string) goto final_exit;
  1594.  
  1595.   if (quoted & Q_KEEP_BACKSLASH)
  1596.     {
  1597.       preserve_backslashes = 1;
  1598.       quoted &= ~Q_KEEP_BACKSLASH;
  1599.     }
  1600.  
  1601.   if (contains_dollar_at)
  1602.     *contains_dollar_at = 0;
  1603.  
  1604.   /* Begin the expansion. */
  1605.  
  1606.   for (;;) {
  1607.  
  1608.     c = string[sindex];
  1609.  
  1610.     switch (c) {        /* Case on toplevel character. */
  1611.  
  1612.     case '\0':
  1613.       goto finished_with_string;
  1614.  
  1615.     case '$':
  1616.  
  1617.       if (expanded_something)
  1618.     *expanded_something = 1;
  1619.  
  1620.       c = string[++sindex];
  1621.  
  1622.       /* Do simple cases first. Switch on what follows '$'. */
  1623.       switch (c)
  1624.     {
  1625.       /* $0 .. $9? */
  1626.     case '0':
  1627.     case '1':
  1628.     case '2':
  1629.     case '3':
  1630.     case '4':
  1631.     case '5':
  1632.     case '6':
  1633.     case '7':
  1634.     case '8':
  1635.     case '9':
  1636.       if (dollar_vars[digit_value (c)])
  1637.         temp = savestring (dollar_vars[digit_value (c)]);
  1638.       else
  1639.         temp = (char *)NULL;
  1640.       goto dollar_add_string;
  1641.  
  1642.     case '$':        /* $$ -- pid of the invoking shell. */
  1643.       {
  1644.         extern int dollar_dollar_pid;
  1645.         number = dollar_dollar_pid;
  1646.       }
  1647.     add_number:
  1648.       temp = itos (number);
  1649.     dollar_add_string:
  1650.       if (string[sindex]) sindex++;
  1651.  
  1652.       /* Add TEMP to ISTRING. */
  1653.     add_string:
  1654.       istring =
  1655.         sub_append_string (temp, istring, &istring_index, &istring_size);
  1656.       break;
  1657.  
  1658.       /* $# -- number of positional parameters. */
  1659.     case '#':
  1660.       {
  1661.         WORD_LIST *list = list_rest_of_args ();
  1662.         number = list_length (list);
  1663.         dispose_words (list);
  1664.         goto add_number;
  1665.       }
  1666.  
  1667.       /* $? -- return value of the last synchronous command. */
  1668.     case '?':
  1669.       number = last_command_exit_value;
  1670.       goto add_number;
  1671.  
  1672.       /* $- -- flags supplied to the shell on invocation or by `set'. */
  1673.     case '-':
  1674.  
  1675.       temp = (char *)which_set_flags ();
  1676.       goto dollar_add_string;
  1677.  
  1678.       /* $! -- Pid of the last asynchronous command. */
  1679.     case '!':
  1680.       {
  1681.         number = (int)last_asynchronous_pid;
  1682.  
  1683.         /* If no asynchronous pids have been created, echo nothing. */
  1684.         if (number == (int)NO_PID)
  1685.           {
  1686.         if (string[sindex])
  1687.           sindex++;
  1688.         if (expanded_something)
  1689.           *expanded_something = 0;
  1690.         break;
  1691.           }
  1692.         goto add_number;
  1693.       }
  1694.  
  1695.       /* The only difference between this and $@ is when the
  1696.          arg is quoted. */
  1697.     case '*':        /* `$*' */
  1698.       temp = string_rest_of_args (quoted);
  1699.  
  1700.       /* In the case of a quoted string, quote the entire arg-list.
  1701.          "$1 $2 $3". */
  1702.       if (quoted && temp)
  1703.         {
  1704.           char *james_brown = temp;
  1705.           temp = quote_string (temp);
  1706.           free (james_brown);
  1707.         }
  1708.       goto dollar_add_string;
  1709.  
  1710.       /* When we have "$@" what we want is "$1" "$2" "$3" ... This
  1711.          means that we have to turn quoting off after we split into
  1712.          the individually quoted arguments so that the final split
  1713.          on the first character of $IFS is still done.  */
  1714.     case '@':        /* `$@' */
  1715.       {
  1716.         WORD_LIST *tlist = list_rest_of_args ();
  1717.         if (quoted && tlist)
  1718.           quote_list (tlist);
  1719.  
  1720.         /* We want to flag the fact that we saw this.  We can't turn off
  1721.            quoting entirely, because other characters in the string might
  1722.            need it (consider "\"$@\""), but we need some way to signal
  1723.            that the final split on the first character of $IFS should be
  1724.            done, even though QUOTED is 1. */
  1725.         if (quoted)
  1726.           quoted_dollar_at = 1;
  1727.         if (contains_dollar_at)
  1728.           *contains_dollar_at = 1;
  1729.         temp = string_list (tlist);
  1730.         goto dollar_add_string;
  1731.       }
  1732.  
  1733.       /* ${[#]name[[:]#[#]%[%]-=?+[word]]} */
  1734.     case '{':
  1735.       {
  1736.         int check_nullness = 0;
  1737.         int var_is_set = 0;
  1738.         int var_is_null = 0;
  1739.         int var_is_special = 0;
  1740.         char *name, *value;
  1741.  
  1742.         sindex++;
  1743.         t_index = sindex;
  1744.         name = string_extract (string, &t_index, "#%:-=?+}");
  1745.  
  1746.         /* If the name really consists of a special variable, then
  1747.            make sure that we have the entire name. */
  1748.         if (sindex == t_index &&
  1749.         (string[sindex] == '-' ||
  1750.          string[sindex] == '?' ||
  1751.          string[sindex] == '#'))
  1752.           {
  1753.         char *tt;
  1754.         t_index++;
  1755.         free (name);
  1756.         tt = (string_extract (string, &t_index, "#%:-=?+}"));
  1757.         name = (char *)xmalloc (2 + (strlen (tt)));
  1758.         *name = string[sindex];
  1759.         strcpy (name + 1, tt);
  1760.         free (tt);
  1761.           }
  1762.         sindex = t_index;
  1763.  
  1764.         /* Find out what character ended the variable name.  Then
  1765.            do the appropriate thing. */
  1766.  
  1767.         if (c = string[sindex])
  1768.           sindex++;
  1769.  
  1770.         if (c == ':')
  1771.           {
  1772.         check_nullness++;
  1773.         if (c = string[sindex])
  1774.           sindex++;
  1775.           }
  1776.  
  1777.         /* Determine the value of this variable. */
  1778.         if (digit (*name) ||
  1779.         (strlen (name) == 1 && member (*name, "#-?$!@*")))
  1780.           var_is_special++;
  1781.  
  1782.         /* Check for special expansion things. */
  1783.         if (*name == '#')
  1784.           {
  1785.         /* Handle ${#-} and ${#?}.  They return the lengths of
  1786.            $- and $?, respectively. */
  1787.         if (string[sindex] == '}' &&
  1788.             !name[1] &&
  1789.             !check_nullness &&
  1790.             (c == '-' || c == '?'))
  1791.           {
  1792.             char *s;
  1793.  
  1794.             free (name);
  1795.  
  1796.             if (c == '-')
  1797.               s = (char *)which_set_flags ();
  1798.             else
  1799.               s = itos (last_command_exit_value);
  1800.  
  1801.             number = s ? strlen (s) : 0;
  1802.             if (s)
  1803.               free (s);
  1804.             goto add_number;
  1805.           }
  1806.  
  1807.         /* Don't allow things like ${#:-foo} to go by; they are
  1808.            errors.  If we are not pointing at the character just
  1809.            after the closing brace, then we haven't gotten all of
  1810.            the name.  Since it begins with a special character,
  1811.            this is a bad substitution.  Explicitly check for ${#:},
  1812.            which the rules do not catch. */
  1813.         if (string[sindex - 1] != '}' || member (c, "?-=+") ||
  1814.             (string[sindex - 1] == '}' && !name[1] && c == '}' &&
  1815.              check_nullness))
  1816.           {
  1817.             free (name);
  1818.             name = string;
  1819.             goto bad_substitution;
  1820.           }
  1821.  
  1822.         number = parameter_brace_expand_length (name);
  1823.         /* We are pointing one character after the brace which
  1824.            closes this expression.  Since the code at add_number
  1825.            increments SINDEX, we back up a single character here. */
  1826.         sindex--;
  1827.         goto add_number;
  1828.           }
  1829.  
  1830.         /* ${@} is identical to $@. */
  1831.         if (name[0] == '@' && name[1] == '\0')
  1832.           {
  1833.         if (quoted)
  1834.           quoted_dollar_at = 1;
  1835.  
  1836.         if (contains_dollar_at)
  1837.           *contains_dollar_at = 1;
  1838.           }
  1839.  
  1840.         temp = parameter_brace_expand_word (name, var_is_special, quoted);
  1841.  
  1842.         if (temp)
  1843.           var_is_set++;
  1844.  
  1845.         if (!var_is_set || !temp || !*temp)
  1846.           var_is_null++;
  1847.  
  1848.         if (!check_nullness)
  1849.           var_is_null = 0;
  1850.  
  1851.         /* Get the rest of the stuff inside the braces. */
  1852.         if (c && c != '}')
  1853.           {
  1854.         /* Scan forward searching for last `{'.  This is a hack,
  1855.            it will always be a hack, and it always has been a hack. */
  1856.         t_index = sindex;
  1857.         value = extract_delimited_string (string, &t_index,
  1858.                           "{", (char *)NULL, "}");
  1859.         sindex = t_index;
  1860.  
  1861.         if (string[sindex] == '}')
  1862.           sindex++;
  1863.         else
  1864.           {
  1865.             if (value)
  1866.               free (value);
  1867.  
  1868.             free (name);
  1869.             name = string;
  1870.             goto bad_substitution;
  1871.           }
  1872.           }
  1873.         else
  1874.           value = (char *)NULL;
  1875.  
  1876.         /* Do the right thing based on which character ended the variable
  1877.            name. */
  1878.         switch (c)
  1879.           {
  1880.           case '\0':
  1881.           bad_substitution:
  1882.         report_error ("%s: bad substitution", name ? name : "??");
  1883.         free (name);
  1884.         longjmp (top_level, DISCARD);
  1885.  
  1886.           case '}':
  1887.         break;
  1888.  
  1889.           case '#':        /* ${param#[#]pattern} */
  1890.           case '%':        /* ${param%[%]pattern} */
  1891.         {
  1892.           char *t;
  1893.           if (!value || !*value || !temp || !*temp)
  1894.             break;
  1895.           t = parameter_brace_remove_pattern (value, temp, c);
  1896.           free (temp);
  1897.           free (value);
  1898.           temp = t;
  1899.         }
  1900.         break;
  1901.  
  1902.           case '-':
  1903.           case '=':
  1904.           case '?':
  1905.           case '+':
  1906.         if (var_is_set && !var_is_null)
  1907.           {
  1908.             /* We don't want the value of the named variable for
  1909.                anything, just the value of the right hand side. */
  1910.             if (c == '+')
  1911.               {
  1912.             if (temp)
  1913.               free (temp);
  1914.             if (value)
  1915.               temp = parameter_brace_expand_rhs (name, value, c, quoted);
  1916.             else
  1917.               temp = (char *)NULL;
  1918.               }
  1919.             /* Otherwise do nothing.  Just use the value in temp. */
  1920.           }
  1921.         else        /* var not set or var is null */
  1922.           {
  1923.             if (temp)
  1924.               free (temp);
  1925.             temp = (char *)NULL;
  1926.             if (c == '=' && var_is_special)
  1927.               {
  1928.             report_error ("$%s: cannot assign in this way", name);
  1929.             free (name);
  1930.             free (value);
  1931.             longjmp (top_level, DISCARD);
  1932.               }
  1933.             else if (c == '?')
  1934.               parameter_brace_expand_error (name, value);
  1935.             else if (c != '+')
  1936.               temp =
  1937.             parameter_brace_expand_rhs (name, value, c, quoted);
  1938.             free (value);
  1939.           }
  1940.         break;
  1941.           }            /* end case on closing character. */
  1942.         free (name);
  1943.         goto add_string;
  1944.       }            /* end case '{' */
  1945.       /* break; */
  1946.  
  1947.     case '(':        /* Do command or arithmetic substitution. */
  1948.       /* We have to extract the contents of this paren substitution. */
  1949.       {
  1950.         char *extract_command_subst ();
  1951.         int old_index = ++sindex;
  1952.  
  1953.         temp = extract_command_subst (string, &old_index);
  1954.         sindex = old_index;
  1955.  
  1956.         /* For the Posix.2-style $(( )) form of arithmetic substitution,
  1957.            extract the expression and pass it to the evaluator. */
  1958.         if (temp && *temp == '(')
  1959.           {
  1960.         char *t = temp + 1;
  1961.         int last = strlen (t) - 1;
  1962.         extern long evalexp ();
  1963.  
  1964.         if (t[last] != ')')
  1965.           {
  1966.             report_error ("%s: bad arithmetic substitution", temp);
  1967.             free (temp);
  1968.             /* XXX - these are mem leaks */
  1969.             longjmp (top_level, DISCARD);
  1970.           }
  1971.  
  1972.         /* Cut off ending `)' */
  1973.         t[last] = '\0';
  1974.  
  1975.         number = (int)evalexp (t);
  1976.         free (temp);
  1977.         goto add_number;
  1978.           }
  1979.  
  1980.         goto handle_command_substitution;
  1981.       }
  1982.  
  1983.       /* Do straight arithmetic substitution. */
  1984.     case '[':
  1985.       /* We have to extract the contents of this
  1986.          arithmetic substitution. */
  1987.       {
  1988.         char *extract_arithmetic_subst (), *t;
  1989.         int old_index = ++sindex;
  1990.         WORD_LIST *l;
  1991.         extern long evalexp ();
  1992.         extern char *this_command_name;
  1993.  
  1994.         temp = extract_arithmetic_subst (string, &old_index);
  1995.         sindex = old_index;
  1996.  
  1997.         /* Do initial variable expansion. */
  1998.         l = expand_string (temp, 1);
  1999.         t = string_list (l);
  2000.         dispose_words (l);
  2001.  
  2002.         /* No error messages. */
  2003.         this_command_name = (char *)NULL;
  2004.         number = (int)evalexp (t);
  2005.         free (t);
  2006.  
  2007.         goto add_number;
  2008.       }
  2009.  
  2010.     default:
  2011.       {
  2012.         /* Find the variable in VARIABLE_LIST. */
  2013.         int old_index = sindex;
  2014.         char *name;
  2015.         SHELL_VAR *var;
  2016.  
  2017.         temp = (char *)NULL;
  2018.  
  2019.         for (;
  2020.          (c = string[sindex]) &&
  2021.          (isletter (c) || digit (c) || c == '_');
  2022.          sindex++);
  2023.         name = (char *)substring (string, old_index, sindex);
  2024.  
  2025.         /* If this isn't a variable name, then just output the `$'. */
  2026.         if (!name || !*name)
  2027.           {
  2028.         free (name);
  2029.         temp = savestring ("$");
  2030.         if (expanded_something)
  2031.           *expanded_something = 0;
  2032.         goto add_string;
  2033.           }
  2034.  
  2035.         /* If the variable exists, return its value cell. */
  2036.         var = find_variable (name);
  2037.  
  2038.         if (var && !invisible_p (var) && value_cell (var))
  2039.           {
  2040.         temp = savestring (value_cell (var));
  2041.         free (name);
  2042.         goto add_string;
  2043.           }
  2044.         else
  2045.           temp = (char *)NULL;
  2046.  
  2047.         if (unbound_vars_is_error)
  2048.           report_error ("%s: unbound variable", name);
  2049.         else
  2050.           goto add_string;
  2051.  
  2052.         free (name);
  2053.         longjmp (top_level, DISCARD);
  2054.       }
  2055.     }
  2056.       break;            /* End case '$': */
  2057.  
  2058.     case '`':            /* Backquoted command substitution. */
  2059.       {
  2060.     sindex++;
  2061.  
  2062.     if (expanded_something)
  2063.       *expanded_something = 1;
  2064.  
  2065.     t_index = sindex;
  2066.     temp = string_extract (string, &t_index, "`");
  2067.     sindex = t_index;
  2068.     de_backslash (temp);
  2069.  
  2070.       handle_command_substitution:
  2071.     command_subst_result = command_substitute (temp, quoted);
  2072.  
  2073.     if (temp)
  2074.       free (temp);
  2075.  
  2076.     temp = command_subst_result;
  2077.  
  2078.     if (string[sindex])
  2079.       sindex++;
  2080.  
  2081.     goto add_string;
  2082.       }
  2083.  
  2084.     case '\\':
  2085.       if (string[sindex + 1] == '\n')
  2086.     {
  2087.       sindex += 2;
  2088.       continue;
  2089.     }
  2090.       else
  2091.     {
  2092.       char *slashify_chars = "";
  2093.  
  2094.       c = string[++sindex];
  2095.  
  2096.       if (quoted == Q_HERE_DOCUMENT)
  2097.         slashify_chars = slashify_in_here_document;
  2098.       else if (quoted == Q_DOUBLE_QUOTES)
  2099.         slashify_chars = slashify_in_quotes;
  2100.  
  2101.       if (preserve_backslashes || (quoted && !member (c, slashify_chars)))
  2102.         {
  2103.           temp = (char *)xmalloc (3);
  2104.           temp[0] = '\\'; temp[1] = c; temp[2] = '\0';
  2105.           if (c)
  2106.         sindex++;
  2107.           goto add_string;
  2108.         }
  2109.       else
  2110.         {
  2111.           /* This character is quoted, so add it in quoted mode. */
  2112.           c = QUOTE_CHAR (c);
  2113.           goto add_character;
  2114.         }
  2115.     }
  2116.  
  2117.     case '"':
  2118.       if (quoted)
  2119.     goto add_character;
  2120.       sindex++;
  2121.       {
  2122.     WORD_LIST *tresult = (WORD_LIST *)NULL;
  2123.  
  2124.     t_index = sindex;
  2125.     temp = string_extract_double_quoted (string, &t_index);
  2126.     sindex = t_index;
  2127.  
  2128.     if (string[sindex])
  2129.       sindex++;
  2130.  
  2131.     if (temp && *temp)
  2132.       {
  2133.         int dollar_at_flag;
  2134.         int quoting_flags = Q_DOUBLE_QUOTES;
  2135.         WORD_DESC *temp_word = make_word (temp);
  2136.  
  2137.         free (temp);
  2138.  
  2139.         if (preserve_backslashes)
  2140.           quoting_flags |= Q_KEEP_BACKSLASH;
  2141.         tresult = expand_word_internal (temp_word, quoting_flags,
  2142.                         &dollar_at_flag, (int *)NULL);
  2143.  
  2144.         dispose_word (temp_word);
  2145.  
  2146.         if (!tresult && dollar_at_flag)
  2147.           break;
  2148.         /* If we get "$@", we know we have expanded something, so we
  2149.            need to remember it for the final split on $IFS.  This is
  2150.            a special case; it's the only case where a quoted string
  2151.            can expand into more than one word.  It's going to come back
  2152.            from the above call to expand_word_internal as a list with
  2153.            a single word, in which all characters are quoted and
  2154.            separated by blanks.  What we want to do is to turn it back
  2155.            into a list for the next piece of code. */
  2156.         dequote_list (tresult);
  2157.         if (dollar_at_flag)
  2158.           quoted_dollar_at++;
  2159.         if (expanded_something)
  2160.           *expanded_something = 1;
  2161.       }
  2162.     else
  2163.       {
  2164.         /* What we have is "".  This is a minor optimization. */
  2165.         free (temp);
  2166.         tresult = (WORD_LIST *)NULL;
  2167.       }
  2168.  
  2169.     /* The code above *might* return a list (consider the case of "$@",
  2170.        where it returns "$1", "$2", etc.).  We can't throw away the rest
  2171.        of the list, and we have to make sure each word gets added as
  2172.        quoted.  We test on tresult->next:  if it is non-NULL, we quote
  2173.        the whole list, save it to a string with string_list, and add that
  2174.        string. We don't need to quote the results of this (and it would be
  2175.        wrong, since that would quote the separators as well), so we go
  2176.        directly to add_string. */
  2177.     if (tresult)
  2178.       {
  2179.         if (tresult->next)
  2180.           {
  2181.         quote_list (tresult);
  2182.         temp = string_list (tresult);
  2183.         dispose_words (tresult);
  2184.         goto add_string;
  2185.           }
  2186.         else
  2187.           {
  2188.         temp = savestring (tresult->word->word);
  2189.         dispose_words (tresult);
  2190.           }
  2191.       }
  2192.     else
  2193.       temp = (char *)NULL;
  2194.  
  2195.       add_quoted_string:
  2196.  
  2197.     if (temp)
  2198.       {
  2199.         char *t = temp;
  2200.         temp = quote_string (temp);
  2201.         free (t);
  2202.       }
  2203.     else
  2204.       {
  2205.         /* Add NULL arg. */
  2206.         temp = savestring (" ");
  2207.         temp[0] = (unsigned char)QUOTE_CHAR ('\0');
  2208.       }
  2209.     goto add_string;
  2210.       }
  2211.       /* break; */
  2212.  
  2213.     case '\'':
  2214.       {
  2215.     if (!quoted)
  2216.       {
  2217.         sindex++;
  2218.  
  2219.         t_index = sindex;
  2220.         temp = string_extract_verbatim (string, &t_index, "'");
  2221.         sindex = t_index;
  2222.  
  2223.         if (string[sindex])
  2224.           sindex++;
  2225.  
  2226.         if (!*temp)
  2227.           {
  2228.         free (temp);
  2229.         temp = (char *)NULL;
  2230.           }
  2231.  
  2232.         goto add_quoted_string;
  2233.       }
  2234.     else
  2235.       goto add_character;
  2236.  
  2237.     break;
  2238.       }
  2239.  
  2240.     default:
  2241.  
  2242.       /* This is the fix for " $@ " */
  2243.       if (quoted)
  2244.     c = QUOTE_CHAR (c);
  2245.  
  2246. add_character:
  2247.       while (istring_index + 1 >= istring_size)
  2248.     istring = (char *)
  2249.       xrealloc (istring, istring_size += DEFAULT_ARRAY_SIZE);
  2250.       istring[istring_index++] = c;
  2251.       istring[istring_index] = '\0';
  2252.  
  2253.       /* Next character. */
  2254.       sindex++;
  2255.     }
  2256.   }
  2257.  
  2258. finished_with_string:
  2259. final_exit:
  2260.   /* OK, we're ready to return.  If we have a quoted string, and
  2261.      quoted_dollar_at is not set, we do no splitting at all; otherwise
  2262.      we split on ' '.  The routines that call this will handle what to
  2263.      do if nothing has been expanded. */
  2264.   if (istring)
  2265.     {
  2266.       WORD_LIST *temp_list;
  2267.  
  2268.       if (quoted_dollar_at)
  2269.     temp_list = list_string (istring, " ", quoted);
  2270.       else if (*istring)
  2271.     {
  2272.       temp_list = make_word_list (make_word (istring), (WORD_LIST *)NULL);
  2273.       temp_list->word->quoted = quoted;
  2274.     }
  2275.       else
  2276.     temp_list = (WORD_LIST *)NULL;
  2277.       free (istring);
  2278.       result = (WORD_LIST *)list_append (reverse_list (result), temp_list);
  2279.     }
  2280.   else
  2281.     result = (WORD_LIST *)NULL;
  2282.  
  2283.   return (result);
  2284. }
  2285.  
  2286. /* **************************************************************** */
  2287. /*                                                                  */
  2288. /*              Functions for Quote Removal                */
  2289. /*                                                                  */
  2290. /* **************************************************************** */
  2291.  
  2292. /* Perform quote removal on STRING.  If QUOTED > 0, assume we are obeying the
  2293.    backslash quoting rules for within double quotes. */
  2294. char *
  2295. string_quote_removal (string, quoted)
  2296.      char *string;
  2297.      int quoted;
  2298. {
  2299.   char *r, *result_string, *temp, *temp1;
  2300.   int sindex, tindex, c;
  2301.  
  2302.   /* The result can be no longer than the original string. */
  2303.   r = result_string = xmalloc (strlen (string) + 1);
  2304.   sindex = 0;
  2305.  
  2306.   for (;;)
  2307.     {
  2308.       c = string[sindex];
  2309.       if (c == '\0')
  2310.     break;
  2311.  
  2312.       switch (c)
  2313.     {
  2314.       case '\\':
  2315.         c = string[++sindex];
  2316.         if (quoted && !member (c, slashify_in_quotes))
  2317.           {
  2318.         *r++ = '\\';
  2319.         *r++ = c;
  2320.           }
  2321.         else
  2322.           *r++ = c;
  2323.  
  2324.         sindex++;
  2325.         break;
  2326.       
  2327.       case '"':
  2328.         tindex = ++sindex;
  2329.         temp = string_extract_double_quoted (string, &tindex);
  2330.         sindex = tindex;
  2331.  
  2332.         if (string[sindex])
  2333.           sindex++;
  2334.  
  2335.         temp1 = string_quote_removal (temp, 1);  /* XXX is this needed? */
  2336.  
  2337.         if (temp)
  2338.           free (temp);
  2339.  
  2340.         if (temp1)
  2341.           {
  2342.         strcpy (r, temp1);
  2343.         r += strlen (r);
  2344.         free (temp1);
  2345.           }
  2346.         break;
  2347.         
  2348.       case '\'':
  2349.         if (quoted)
  2350.           {
  2351.         *r++ = c;
  2352.         sindex++;
  2353.           }
  2354.         else
  2355.           {
  2356.         tindex = ++sindex;
  2357.         temp = string_extract_verbatim (string, &tindex, "'");
  2358.         sindex = tindex;
  2359.  
  2360.         if (string[sindex])
  2361.           sindex++;
  2362.  
  2363.         if (temp)
  2364.           {
  2365.             strcpy (r, temp);
  2366.             r += strlen (r);
  2367.             free (temp);
  2368.           }
  2369.           }
  2370.         break;
  2371.       default:
  2372.         *r++ = c;
  2373.         sindex++;
  2374.         break;
  2375.     }
  2376.     }
  2377.     *r = '\0';
  2378.     return (result_string);
  2379. }
  2380.  
  2381. /* Perform quote removal on word WORD.  This allocates and returns a new
  2382.    WORD_DESC *. */
  2383. WORD_DESC *
  2384. word_quote_removal (word, quoted)
  2385.      WORD_DESC *word;
  2386.      int quoted;
  2387. {
  2388.   WORD_DESC *w;
  2389.   char *t;
  2390.  
  2391.   t = string_quote_removal (word->word, quoted);
  2392.   w = make_word (t);
  2393.   return (w);
  2394. }
  2395.  
  2396. /* Perform quote removal on all words in LIST.  If QUOTED is non-zero,
  2397.    the members of the list are treated as if they are surrounded by
  2398.    double quotes.  Return a new list, or NULL if LIST is NULL. */
  2399. WORD_LIST *
  2400. word_list_quote_removal (list, quoted)
  2401.      WORD_LIST *list;
  2402.      int quoted;
  2403. {
  2404.   WORD_LIST *result = (WORD_LIST *)NULL, *t, *tresult;
  2405.  
  2406.   t = list;
  2407.   while (t)
  2408.     {
  2409.       tresult = (WORD_LIST *)xmalloc (sizeof (WORD_LIST));
  2410.       tresult->word = word_quote_removal (t->word, quoted);
  2411.       tresult->next = (WORD_LIST *)NULL;
  2412.       result = (WORD_LIST *) list_append (result, tresult);
  2413.       t = t->next;
  2414.     }
  2415.   return (result);
  2416. }
  2417.  
  2418. #if defined (NOTDEF)
  2419. /* Currently unused. */
  2420. /* Return 1 if CHARACTER appears in an unquoted portion of
  2421.    STRING.  Return 0 otherwise. */
  2422. static int
  2423. unquoted_member (character, string)
  2424.      int character;
  2425.      char *string;
  2426. {
  2427.   int sindex, tindex, c;
  2428.   char *temp;
  2429.  
  2430.   sindex = 0;
  2431.  
  2432.   while (c = string[sindex])
  2433.     {
  2434.       if (c == character)
  2435.     return (1);
  2436.  
  2437.       switch (c)
  2438.     {
  2439.       case '\\':
  2440.         sindex++;
  2441.         if (string[sindex])
  2442.           sindex++;
  2443.         break;
  2444.       
  2445.       case '"':
  2446.       case '\'':
  2447.  
  2448.         tindex = ++sindex;
  2449.         if (c == '"')
  2450.           temp = string_extract_double_quoted (string, &tindex);
  2451.         else
  2452.           temp = string_extract_verbatim (string, &tindex, "'");
  2453.         sindex = tindex;
  2454.  
  2455.         if (string[sindex])
  2456.           sindex++;
  2457.  
  2458.         if (temp)
  2459.           free (temp);
  2460.         break;
  2461.         
  2462.       default:
  2463.         sindex++;
  2464.         break;
  2465.     }
  2466.     }
  2467.   return (0);
  2468. }
  2469. #endif /* NOTDEF */
  2470.  
  2471. /* Return 1 if SUBSTR appears in an unquoted portion of STRING. */
  2472. static int
  2473. unquoted_substring (substr, string)
  2474.      char *substr, *string;
  2475. {
  2476.   int sindex, tindex, c, sublen;
  2477.   char *temp;
  2478.  
  2479.   if (!substr || !*substr)
  2480.     return (0);
  2481.  
  2482.   sublen = strlen (substr);
  2483.   sindex = 0;
  2484.  
  2485.   while (c = string[sindex])
  2486.     {
  2487.       if (c == *substr &&
  2488.       strncmp (string + sindex, substr, sublen) == 0)
  2489.     return (1);
  2490.  
  2491.       switch (c)
  2492.     {
  2493.       case '\\':
  2494.         sindex++;
  2495.  
  2496.         if (string[sindex])
  2497.           sindex++;
  2498.         break;
  2499.       
  2500.       case '"':
  2501.       case '\'':
  2502.  
  2503.         tindex = ++sindex;
  2504.         if (c == '"')
  2505.           temp = string_extract_double_quoted (string, &tindex);
  2506.         else
  2507.           temp = string_extract_verbatim (string, &tindex, "'");
  2508.         sindex = tindex;
  2509.  
  2510.         if (string[sindex])
  2511.           sindex++;
  2512.  
  2513.         if (temp)
  2514.           free (temp);
  2515.  
  2516.         break;
  2517.         
  2518.       default:
  2519.         sindex++;
  2520.         break;
  2521.     }
  2522.     }
  2523.   return (0);
  2524. }
  2525.  
  2526. /*******************************************
  2527.  *                       *
  2528.  *    Functions to perform word splitting  *
  2529.  *                       *
  2530.  *******************************************/
  2531.  
  2532. /* This splits a single word into a WORD LIST on $IFS, but only if the word
  2533.    is not quoted.  list_string () performs quote removal for us, even if we
  2534.    don't do any splitting. */
  2535. WORD_LIST *
  2536. word_split (w)
  2537.      WORD_DESC *w;
  2538. {
  2539.   WORD_LIST *result;
  2540.  
  2541.   if (w)
  2542.     {
  2543.       SHELL_VAR *ifs = find_variable ("IFS");
  2544.       char *ifs_chars;
  2545.  
  2546.       /* If IFS is unset, it defaults to " \t\n". */
  2547.       if (ifs)
  2548.     ifs_chars = value_cell (ifs);
  2549.       else
  2550.     ifs_chars = " \t\n";
  2551.  
  2552.       if (w->quoted || !ifs_chars)
  2553.     ifs_chars = "";
  2554.  
  2555.       result = list_string (w->word, ifs_chars, w->quoted);
  2556.     }
  2557.   else
  2558.     result = (WORD_LIST *)NULL;
  2559.   return (result);
  2560. }
  2561.  
  2562. /* Perform word splitting on LIST and return the RESULT.  It is possible
  2563.    to return (WORD_LIST *)NULL. */
  2564. WORD_LIST *
  2565. word_list_split (list)
  2566.      WORD_LIST *list;
  2567. {
  2568.   WORD_LIST *result = (WORD_LIST *)NULL, *t, *tresult;
  2569.  
  2570.   t = list;
  2571.   while (t)
  2572.     {
  2573.       tresult = word_split (t->word);
  2574.       result = (WORD_LIST *) list_append (result, tresult);
  2575.       t = t->next;
  2576.     }
  2577.   return (result);
  2578. }
  2579.  
  2580. /**************************************************
  2581.  *                           *
  2582.  *    Functions to expand an entire WORD_LIST      *
  2583.  *                          *
  2584.  **************************************************/
  2585.  
  2586. /* Do all of the assignments in LIST up to a word which isn't an
  2587.    assignment. */
  2588. WORD_LIST *
  2589. get_rid_of_variable_assignments (list)
  2590.      WORD_LIST *list;
  2591. {
  2592.   WORD_LIST *orig = list;
  2593.  
  2594.   while (list)
  2595.     if (!list->word->assignment)
  2596.       {
  2597.     WORD_LIST *new_list = copy_word_list (list);
  2598.     dispose_words (orig);
  2599.     return (new_list);
  2600.       }
  2601.     else
  2602.       {
  2603.     do_assignment (list->word->word);
  2604.     list = list->next;
  2605.       }
  2606.   dispose_words (orig);
  2607.   return ((WORD_LIST *)NULL);
  2608. }
  2609.  
  2610. /* Check and handle the case where there are some variable assignments
  2611.    in LIST which go into the environment for this command. */
  2612. WORD_LIST *
  2613. get_rid_of_environment_assignments (list)
  2614.      WORD_LIST *list;
  2615. {
  2616.   register WORD_LIST *tlist = list;
  2617.   register WORD_LIST *new_list;
  2618.  
  2619.   while (tlist)
  2620.     {
  2621.       if (!tlist->word->assignment) goto make_assignments;
  2622.       tlist = tlist->next;
  2623.     }
  2624.   /* Since all of the assignments are variable assignments. */
  2625.   return (list);
  2626.  
  2627. make_assignments:
  2628.   tlist = list;
  2629.   while (tlist)
  2630.     {
  2631.       if (tlist->word->assignment)
  2632.     assign_in_env (tlist->word->word);
  2633.       else
  2634.     {
  2635.       if (!place_keywords_in_env)
  2636.         {
  2637.           new_list = copy_word_list (tlist);
  2638.           dispose_words (list);
  2639.           return (new_list);
  2640.         }
  2641.     }
  2642.       tlist = tlist->next;
  2643.     }
  2644.  
  2645.   /* We got all of the keywords assigned.  Now return the remainder
  2646.      of the words. */
  2647.   {
  2648.     register WORD_LIST *new_list = (WORD_LIST *)NULL;
  2649.  
  2650.     tlist = list;
  2651.  
  2652.     /* Skip the ones at the start. */
  2653.     while (tlist && tlist->word->assignment)
  2654.       tlist = tlist->next;
  2655.  
  2656.     /* If we placed all the keywords in the list into the environment,
  2657.        then remove them from the output list. */
  2658.     if (place_keywords_in_env)
  2659.       {
  2660.     while (tlist)
  2661.       {
  2662.         if (!tlist->word->assignment)
  2663.           new_list = make_word_list (copy_word (tlist->word), new_list);
  2664.         tlist = tlist->next;
  2665.       }
  2666.     new_list = (WORD_LIST *)reverse_list (new_list);
  2667.       }
  2668.     else
  2669.       {
  2670.     /* Just copy the list. */
  2671.     new_list = copy_word_list (tlist);
  2672.       }
  2673.     dispose_words (list);
  2674.     return (new_list);
  2675.   }
  2676. }
  2677.  
  2678. /* Take the list of words in LIST and do the various substitutions.  Return
  2679.    a new list of words which is the expanded list, and without things like
  2680.    variable assignments. */
  2681. static WORD_LIST *expand_words_internal ();
  2682.  
  2683. WORD_LIST *
  2684. expand_words (list)
  2685.      WORD_LIST *list;
  2686. {
  2687.   return (expand_words_internal (list, 1));
  2688. }
  2689.  
  2690. /* Same as expand_words (), but doesn't hack variable or environment
  2691.    variables. */
  2692. WORD_LIST *
  2693. expand_words_no_vars (list)
  2694.      WORD_LIST *list;
  2695. {
  2696.   return (expand_words_internal (list, 0));
  2697. }
  2698.  
  2699. /* Non-zero means to allow unmatched globbed filenames to expand to
  2700.    a null file. */
  2701. static int allow_null_glob_expansion = 0;
  2702.  
  2703. /* The workhorse for expand_words () and expand_words_no_var ().
  2704.    First arg is LIST, a WORD_LIST of words.
  2705.    Second arg DO_VARS is non-zero if you want to do environment and
  2706.    variable assignments, else zero.
  2707.  
  2708.    This does all of the subsitutions: brace expansion, tilde expansion,
  2709.    parameter expansion, command substitution, arithmetic expansion,
  2710.    word splitting, and pathname expansion. */
  2711. static WORD_LIST *
  2712. expand_words_internal (list, do_vars)
  2713.      WORD_LIST *list;
  2714.      int do_vars;
  2715. {
  2716.   register WORD_LIST *tlist, *new_list = (WORD_LIST *)NULL;
  2717.   WORD_LIST *orig_list;
  2718.   extern int no_brace_expansion;
  2719.  
  2720.   tlist = (WORD_LIST *)copy_word_list (list);
  2721.  
  2722.   if (do_vars)
  2723.     {
  2724.       /* Handle the case where the arguments are assignments for
  2725.      the environment of this command. */
  2726.       tlist = get_rid_of_environment_assignments (tlist);
  2727.  
  2728.       /* Handle the case where the arguments are all variable assignments. */
  2729.       tlist = get_rid_of_variable_assignments (tlist);
  2730.     }
  2731.  
  2732.   /* Begin expanding the words that remain.  The expansions take place on
  2733.      things that aren't really variable assignments. */
  2734.  
  2735.   if (!tlist)
  2736.     return ((WORD_LIST *)NULL);
  2737.  
  2738.   /* Do brace expansion on this word if there are any brace characters
  2739.      in the string. */
  2740.   if (!no_brace_expansion)
  2741.     {
  2742.       extern char **brace_expand ();
  2743.       register char **expansions;
  2744.       WORD_LIST *braces = (WORD_LIST *)NULL;
  2745.       int eindex;
  2746.  
  2747.       orig_list = tlist;
  2748.  
  2749.       while (tlist)
  2750.     {
  2751.       /* Only do brace expansion if the word has a brace character.  If
  2752.          not, just copy the word list element, add it to braces, and
  2753.          continue.  In the common case, at least when running shell
  2754.          scripts, this will degenerate to a bunch of calls to `index',
  2755.          and then what is basically the body of copy_word_list. */
  2756.       if (index (tlist->word->word, '{') != NULL)
  2757.         {
  2758.           expansions = brace_expand (tlist->word->word);
  2759.  
  2760.           for (eindex = 0; expansions[eindex]; eindex++)
  2761.         {
  2762.           braces = make_word_list (make_word (expansions[eindex]),
  2763.                          braces);
  2764.           free (expansions[eindex]);
  2765.         }
  2766.           free (expansions);
  2767.         }
  2768.       else
  2769.         {
  2770.           WORD_LIST *new = (WORD_LIST *)xmalloc (sizeof (WORD_LIST));
  2771.           new->word = copy_word (tlist->word);
  2772.           new->next = braces;
  2773.           braces = new;
  2774.         }
  2775.  
  2776.       tlist = tlist->next;
  2777.     }
  2778.       dispose_words (orig_list);
  2779.       tlist = (WORD_LIST *)reverse_list (braces);
  2780.     }
  2781.  
  2782.   orig_list = tlist;
  2783.  
  2784.   /* We do tilde expansion all the time.  This is what 1003.2 says. */
  2785.   while (tlist)
  2786.     {
  2787.       register char *current_word;
  2788.       WORD_LIST *expanded, *t;
  2789.       int expanded_something = 0;
  2790.  
  2791.       current_word = tlist->word->word;
  2792.  
  2793.       if (current_word[0] == '~' ||
  2794.       (index (current_word, '~') &&
  2795.        unquoted_substring ("=~", current_word)))
  2796.     {
  2797.       char *tilde_expand (), *tt;
  2798.  
  2799.       tt = tlist->word->word;
  2800.       tlist->word->word = tilde_expand (tt);
  2801.       free (tt);
  2802.     }
  2803.  
  2804.       expanded = expand_word_internal
  2805.     (tlist->word, 0, (int *)NULL, &expanded_something);
  2806.  
  2807.       if (expanded_something)
  2808.     t = word_list_split (expanded);
  2809.       else
  2810.     {
  2811.       /* If no parameter expansion, command substitution, or arithmetic
  2812.          substitution took place, then do not do word splitting.  We
  2813.          still have to remove quoted null characters from the result. */
  2814.       word_list_remove_quoted_nulls (expanded);
  2815.       t = copy_word_list (expanded);
  2816.     }
  2817.  
  2818.       new_list =
  2819.     (WORD_LIST *)list_append (reverse_list (t), new_list);
  2820.  
  2821.       dispose_words (expanded);
  2822.  
  2823.       tlist = tlist->next;
  2824.     }
  2825.  
  2826.   new_list = (WORD_LIST *)reverse_list (new_list);
  2827.  
  2828.   dispose_words (orig_list);
  2829.  
  2830.   /* Okay, we're almost done.  Now let's just do some filename
  2831.      globbing. */
  2832.   {
  2833.     char **shell_glob_filename (), **temp_list = (char **)NULL;
  2834.     register int list_index;
  2835.     WORD_LIST *glob_list;
  2836.  
  2837.     orig_list = (WORD_LIST *)NULL;
  2838.     tlist = new_list;
  2839.  
  2840.     if (!disallow_filename_globbing)
  2841.       {
  2842.     while (tlist)
  2843.       {
  2844.         /* If the word isn't quoted, then glob it. */
  2845.         if (!tlist->word->quoted && glob_pattern_p (tlist->word->word, 0))
  2846.           {
  2847.         temp_list = shell_glob_filename (tlist->word->word);
  2848.  
  2849.         /* Fix the hi-bits. (This is how we quoted
  2850.            special characters.) */
  2851.         {
  2852.           register char *t = dequote_string (tlist->word->word);
  2853.           free (tlist->word->word);
  2854.           tlist->word->word = t;
  2855.         }
  2856.  
  2857.         /* Handle error cases.
  2858.            I don't think we should report errors like "No such file
  2859.            or directory".  However, I would like to report errors
  2860.            like "Read failed". */
  2861.  
  2862. #if defined (USE_GLOB_LIBRARY)
  2863.         if (!temp_list)
  2864. #else
  2865.         if (temp_list == (char **)-1)
  2866. #endif /* !USE_GLOB_LIBRARY */
  2867.           {
  2868.             /* file_error (tlist->word->word); */
  2869.             /* A small memory leak, I think */
  2870.             temp_list = (char **) xmalloc (sizeof (char *));
  2871.             temp_list[0] = '\0';
  2872.           }
  2873.  
  2874. #if !defined (USE_GLOB_LIBRARY)
  2875.         if (!temp_list)
  2876.           abort ();
  2877. #endif /* !USE_GLOB_LIBRARY */
  2878.  
  2879.         /* Make the array into a word list. */
  2880.         glob_list = (WORD_LIST *)NULL;
  2881.         for (list_index = 0; temp_list[list_index]; list_index++)
  2882.           glob_list =
  2883.             make_word_list (make_word (temp_list[list_index]), glob_list);
  2884.  
  2885.         if (glob_list)
  2886.           orig_list = (WORD_LIST *)list_append (glob_list, orig_list);
  2887.         else
  2888.           if (!allow_null_glob_expansion)
  2889.             orig_list =
  2890.               make_word_list (copy_word (tlist->word), orig_list);
  2891.           }
  2892.         else
  2893.           {
  2894.         /* Fix the hi-bits. (This is how we quoted special
  2895.            characters.) */
  2896.         register char *t = dequote_string (tlist->word->word);
  2897.         free (tlist->word->word);
  2898.         tlist->word->word = t;
  2899.         orig_list = make_word_list (copy_word (tlist->word), orig_list);
  2900.           }
  2901.  
  2902.         free_array (temp_list);
  2903.         temp_list = (char **)NULL;
  2904.  
  2905.         tlist = tlist->next;
  2906.       }
  2907.     dispose_words (new_list);
  2908.     new_list = orig_list;
  2909.       }
  2910.     else
  2911.       {
  2912.     /* Fix the hi-bits. (This is how we quoted special characters.) */
  2913.     register WORD_LIST *wl = new_list;
  2914.     register char *wp;
  2915.     while (wl)
  2916.       {
  2917.         wp = dequote_string (wl->word->word);
  2918.         free (wl->word->word);
  2919.         wl->word->word = wp;
  2920.         wl = wl->next;
  2921.       }
  2922.     return (new_list);
  2923.       }
  2924.   }
  2925.   return (WORD_LIST *)(reverse_list (new_list));
  2926. }
  2927.  
  2928. /* Call the glob library to do globbing on PATHNAME.
  2929.    PATHNAME can contain characters with the hi bit set; this indicates
  2930.    that the character is to be quoted.  We quote it here. */
  2931. char **
  2932. shell_glob_filename (pathname)
  2933.      char *pathname;
  2934. #if defined (USE_GLOB_LIBRARY)
  2935. {
  2936.   extern int glob_dot_filenames;
  2937.   register int i, j;
  2938.   char *temp, **return_value;
  2939.   glob_t filenames;
  2940.   int glob_flags;
  2941.  
  2942.   temp = (char *)alloca (1 + (2 * strlen (pathname)));
  2943.  
  2944.   for (i = j = 0; pathname[i]; i++, j++)
  2945.     {
  2946.       if (QUOTED_CHAR (pathname[i]))
  2947.     temp[j++] = '\\';
  2948.  
  2949.       temp[j] = DEQUOTE_CHAR (pathname[i]);
  2950.     }
  2951.   temp[j] = '\0';
  2952.  
  2953.   filenames.gl_offs = 0;
  2954.  
  2955.   glob_flags = glob_dot_filenames ? GLOB_PERIOD : 0;
  2956.   glob_flags |= (GLOB_ERR | GLOB_DOOFFS);
  2957.  
  2958.   i = glob (temp, glob_flags, (Function *)NULL, &filenames);
  2959.  
  2960.   if (i == GLOB_NOSPACE || i == GLOB_ABEND)
  2961.     return ((char **)NULL);
  2962.  
  2963.   if (i == GLOB_NOMATCH)
  2964.     filenames.gl_pathv[0] = (char *)NULL;
  2965.  
  2966.   return (filenames.gl_pathv);
  2967. }
  2968. #else /* !USE_GLOB_LIBRARY */
  2969. {
  2970.   extern char **glob_filename ();
  2971.   extern int glob_dot_filenames, noglob_dot_filenames;
  2972.   register int i, j;
  2973.   char *temp, **results;
  2974.  
  2975.   temp = (char *)alloca (1 + (2 * strlen (pathname)));
  2976.  
  2977.   noglob_dot_filenames = !glob_dot_filenames;
  2978.  
  2979.   for (i = j = 0; pathname[i]; i++, j++)
  2980.     {
  2981.       if (QUOTED_CHAR (pathname[i]))
  2982.     {
  2983.       temp[j++] = '\\';
  2984.       temp[j] = DEQUOTE_CHAR (pathname[i]);
  2985.     }
  2986.       else
  2987.     temp[j] = pathname[i];
  2988.     }
  2989.   temp[j] = '\0';
  2990.  
  2991.   results = glob_filename (temp);
  2992.  
  2993.   if (results && results != (char **)-1)
  2994.     sort_char_array (results);
  2995.  
  2996.   return (results);
  2997. }
  2998. #endif /* !USE_GLOB_LIBRARY */
  2999.  
  3000. /*************************************************
  3001.  *                         *
  3002.  *    Functions to manage special variables     *
  3003.  *                         *
  3004.  *************************************************/
  3005.  
  3006. /* An alist of name.function for each special variable.  Most of the
  3007.    functions don't do much, and in fact, this would be faster with a
  3008.    switch statement, but by the end of this file, I am sick of switch
  3009.    statements. */
  3010.  
  3011. /* The functions that get called. */
  3012. int
  3013.   sv_path (), sv_mail (), sv_terminal (), sv_histsize (), sv_histfilesize (),
  3014.   sv_uids (), sv_ignoreeof (), sv_glob_dot_filenames (), sv_histchars (),
  3015.   sv_nolinks (), sv_hostname_completion_file (), sv_history_control (),
  3016.   sv_noclobber (), sv_allow_null_glob_expansion (),
  3017.   sv_command_oriented_history ();
  3018.  
  3019. #if defined (GETOPTS_BUILTIN)
  3020. int sv_optind (), sv_opterr ();
  3021. #endif /* GETOPTS_BUILTIN */
  3022.  
  3023. #if defined (JOB_CONTROL)
  3024. extern int sv_notify ();
  3025. #endif
  3026.  
  3027. struct name_and_function {
  3028.   char *name;
  3029.   Function *function;
  3030. } special_vars[] = {
  3031.   { "PATH", sv_path },
  3032.   { "MAIL", sv_mail },
  3033.   { "MAILPATH", sv_mail },
  3034.   { "MAILCHECK", sv_mail },
  3035.   { "TERMCAP", sv_terminal },
  3036.   { "TERM", sv_terminal },
  3037.   { "HISTSIZE", sv_histsize },
  3038.   { "HISTFILESIZE", sv_histfilesize },
  3039.   { "EUID", sv_uids},
  3040.   { "UID", sv_uids},
  3041.   { "IGNOREEOF", sv_ignoreeof },
  3042.   { "ignoreeof", sv_ignoreeof },
  3043. #if defined (GETOPTS_BUILTIN)
  3044.   { "OPTIND", sv_optind },
  3045.   { "OPTERR", sv_opterr },
  3046. #endif /* GETOPTS_BUILTIN */
  3047. #if defined (JOB_CONTROL)
  3048.   { "notify", sv_notify },
  3049. #endif  /* JOB_CONTROL */
  3050.   { "glob_dot_filenames", sv_glob_dot_filenames },
  3051.   { "allow_null_glob_expansion", sv_allow_null_glob_expansion },
  3052.   { "command_oriented_history", sv_command_oriented_history },
  3053.   { "histchars", sv_histchars },
  3054.   { "hostname_completion_file", sv_hostname_completion_file },
  3055.   { "history_control", sv_history_control },
  3056.   { "noclobber", sv_noclobber },
  3057.   { "nolinks", sv_nolinks },
  3058.   { (char *)0x00, (Function *)0x00 }
  3059. };
  3060.  
  3061. /* The variable in NAME has just had its state changed.  Check to see if it
  3062.    is one of the special ones where something special happens. */
  3063. stupidly_hack_special_variables (name)
  3064.      char *name;
  3065. {
  3066.   int i = 0;
  3067.  
  3068.   while (special_vars[i].name)
  3069.     {
  3070.       if (STREQ (special_vars[i].name, name))
  3071.     {
  3072.       (*(special_vars[i].function)) (name);
  3073.       return;
  3074.     }
  3075.       i++;
  3076.     }
  3077. }
  3078.  
  3079. /* Set/unset noclobber. */
  3080. sv_noclobber (name)
  3081.      char *name;
  3082. {
  3083.   extern int noclobber;
  3084.  
  3085.   if (find_variable (name))
  3086.     noclobber = 1;
  3087.   else
  3088.     noclobber = 0;
  3089. }
  3090.  
  3091. /* What to do just after the PATH variable has changed. */
  3092. sv_path (name)
  3093.      char *name;
  3094. {
  3095.   /* hash -r */
  3096.   WORD_LIST *args;
  3097.  
  3098.   args = make_word_list (make_word ("-r"), NULL);
  3099.   hash_builtin (args);
  3100.   dispose_words (args);
  3101. }
  3102.  
  3103. /* What to do just after one of the MAILxxxx variables has changed.  NAME
  3104.    is the name of the variable.  */
  3105. sv_mail (name)
  3106.      char *name;
  3107. {
  3108.   /* If the time interval for checking the files has changed, then
  3109.      reset the mail timer.  Otherwise, one of the pathname vars
  3110.      to the users mailbox has changed, so rebuild the array of
  3111.      filenames. */
  3112.   if (strcmp (name, "MAILCHECK") == 0)
  3113.     reset_mail_timer ();
  3114.   else
  3115.     {
  3116.       if ((strcmp (name, "MAIL") == 0) || (strcmp (name, "MAILPATH") == 0))
  3117.     {
  3118.       free_mail_files ();
  3119.       remember_mail_dates ();
  3120.     }
  3121.     }
  3122. }
  3123.  
  3124. /* What to do just after one of the TERMxxx variables has changed.
  3125.    If we are an interactive shell, then try to reset the terminal
  3126.    information in readline. */
  3127. sv_terminal (name)
  3128.      char *name;
  3129. {
  3130.   extern int interactive;
  3131.  
  3132.   if (interactive)
  3133.     rl_reset_terminal (get_string_value ("TERM"));
  3134. }
  3135.  
  3136. /* What to do after the HISTSIZE variable changes.
  3137.    If there is a value for this variable (and it is numeric), then stifle
  3138.    the history.  Otherwise, if there is NO value for this variable,
  3139.    unstifle the history. */
  3140. sv_histsize (name)
  3141.      char *name;
  3142. {
  3143.   char *temp = get_string_value (name);
  3144.  
  3145.   if (temp)
  3146.     {
  3147.       int num;
  3148.       if (sscanf (temp, "%d", &num) == 1)
  3149.     {
  3150.       extern int history_lines_this_session;
  3151.  
  3152.       stifle_history (num);
  3153.       if (history_lines_this_session > where_history ())
  3154.         history_lines_this_session = where_history ();
  3155.     }
  3156.     }
  3157.   else
  3158.     unstifle_history ();
  3159. }
  3160.  
  3161. /* What to do if the HISTFILESIZE variable changes. */
  3162. sv_histfilesize (name)
  3163.      char *name;
  3164. {
  3165.   char *temp = get_string_value (name);
  3166.  
  3167.   if (temp)
  3168.     {
  3169.       extern int history_lines_in_file;
  3170.       int num;
  3171.       if (sscanf (temp, "%d", &num) == 1)
  3172.     {
  3173.       history_truncate_file (get_string_value ("HISTFILE"), num);
  3174.       if (num <= history_lines_in_file)
  3175.         history_lines_in_file = num;
  3176.     }
  3177.     }
  3178. }
  3179.  
  3180. /* A nit for picking at history saving.
  3181.    Value of 0 means save all lines parsed by the shell on the history.
  3182.    Value of 1 means save all lines that do not start with a space.
  3183.    Value of 2 means save all lines that do not match the last line saved. */
  3184. int history_control = 0;
  3185.  
  3186. /* What to do after the HISTORY_CONTROL variable changes. */
  3187. sv_history_control (name)
  3188.      char *name;
  3189. {
  3190.   char *temp = get_string_value (name);
  3191.  
  3192.   history_control = 0;
  3193.  
  3194.   if (temp && *temp)
  3195.     {
  3196.       if (strcmp (temp, "ignorespace") == 0)
  3197.     history_control = 1;
  3198.       else if (strcmp (temp, "ignoredups") == 0)
  3199.     history_control = 2;
  3200.     }
  3201. }
  3202.  
  3203. /* By default, every line is saved in the history individually.  I.e.,
  3204.    if the user enters:
  3205.     bash$ for i in a b c
  3206.         > do
  3207.         > echo $i
  3208.         > done
  3209.    Each line will be individually saved in the history. 
  3210.     bash$ history
  3211.     10  for i in a b c
  3212.         11  do
  3213.         12  echo $i
  3214.         13  done
  3215.         14  history
  3216.    If the variable command_oriented_history is set, multiple lines
  3217.    which form one command will be saved as one history entry.
  3218.     bash$ for i in a b c
  3219.         > do
  3220.         > echo $i
  3221.         > done
  3222.         bash$ history
  3223.     10  for i in a b c
  3224.     do
  3225.     echo $i
  3226.     done
  3227.         11  history
  3228.    The user can then recall the whole command all at once instead
  3229.    of just being able to recall one line at a time.
  3230.    */
  3231. int command_oriented_history = 0;
  3232.  
  3233. /* What to do after the COMMAND_ORIENTED_HISTORY variable changes. */
  3234. sv_command_oriented_history (name)
  3235.      char *name;
  3236. {
  3237.   if (find_variable (name) != (SHELL_VAR *)NULL)
  3238.     command_oriented_history = 1;
  3239.   else
  3240.     command_oriented_history = 0;
  3241. }
  3242.  
  3243. /* If the variable exists, then the value of it can be the number
  3244.    of times we actually ignore the EOF.  The default is small,
  3245.    (smaller than csh, anyway). */
  3246. sv_ignoreeof (name)
  3247.      char *name;
  3248. {
  3249.   extern int eof_encountered, eof_encountered_limit;
  3250.   char *temp = get_string_value (name);
  3251.   int new_limit;
  3252.  
  3253.   eof_encountered = 0;
  3254.  
  3255.   if (temp && (sscanf (temp, "%d", &new_limit) == 1))
  3256.     eof_encountered_limit = new_limit;
  3257.   else
  3258.     eof_encountered_limit = 10; /* csh uses 26. */
  3259. }
  3260.  
  3261. /* Control whether * matches .files in globbing.  Yechh. */
  3262. int glob_dot_filenames = 0;
  3263.  
  3264. sv_glob_dot_filenames (name)
  3265.      char *name;
  3266. {
  3267.   if (find_variable (name) != (SHELL_VAR *)NULL)
  3268.     glob_dot_filenames = 1;
  3269.   else
  3270.     glob_dot_filenames = 0;
  3271. }
  3272.  
  3273. /* Setting/unsetting of the history expansion character. */
  3274. char old_history_expansion_char = '!';
  3275. char old_history_comment_char = '#';
  3276. char old_history_subst_char = '^';
  3277.  
  3278. sv_histchars (name)
  3279.      char *name;
  3280. {
  3281.   extern char history_expansion_char;
  3282.   extern char history_comment_char;
  3283.   extern char history_subst_char;
  3284.   char *temp = get_string_value (name);
  3285.  
  3286.   if (temp)
  3287.     {
  3288.       old_history_expansion_char = history_expansion_char;
  3289.       history_expansion_char = *temp;
  3290.  
  3291.       if (temp[1])
  3292.     {
  3293.       old_history_subst_char = history_subst_char;
  3294.       history_subst_char = temp[1];
  3295.  
  3296.       if (temp[2])
  3297.         {
  3298.           old_history_comment_char = history_comment_char;
  3299.           history_comment_char = temp[2];
  3300.         }
  3301.     }
  3302.     }
  3303.   else
  3304.     {
  3305.       history_expansion_char = '!';
  3306.       history_subst_char = '^';
  3307.       history_comment_char = '#';
  3308.     }
  3309. }
  3310.  
  3311. #if defined (JOB_CONTROL)
  3312. /* Job notification feature desired? */
  3313. sv_notify (name)
  3314.      char *name;
  3315. {
  3316.   extern int asynchronous_notification;
  3317.  
  3318.   if (get_string_value (name))
  3319.     asynchronous_notification = 1;
  3320.   else
  3321.     asynchronous_notification = 0;
  3322. }
  3323. #endif  /* JOB_CONTROL */
  3324.  
  3325. /* If the variable `nolinks' exists, it specifies that symbolic links are
  3326.    not to be followed in `cd' commands. */
  3327. sv_nolinks (name)
  3328.      char *name;
  3329. {
  3330.   extern int follow_symbolic_links;
  3331.  
  3332.   follow_symbolic_links = !find_variable (name);
  3333. }
  3334.  
  3335. /* Don't let users hack the user id variables. */
  3336. sv_uids (name)
  3337.      char *name;
  3338. {
  3339.   int uid = getuid ();
  3340.   int euid = geteuid ();
  3341.   char buff[10];
  3342.   register SHELL_VAR *v;
  3343.  
  3344.   sprintf (buff, "%d", uid);
  3345.   v = find_variable ("UID");
  3346.   if (v)
  3347.     v->attributes &= ~att_readonly;
  3348.  
  3349.   v = bind_variable ("UID", buff);
  3350.   v->attributes |= (att_readonly | att_integer);
  3351.  
  3352.   sprintf (buff, "%d", euid);
  3353.   v = find_variable ("EUID");
  3354.   if (v)
  3355.     v->attributes &= ~att_readonly;
  3356.  
  3357.   v = bind_variable ("EUID", buff);
  3358.   v->attributes |= (att_readonly | att_integer);
  3359. }
  3360.  
  3361. sv_hostname_completion_file (name)
  3362.      char *name;
  3363. {
  3364.   extern int hostname_list_initialized;
  3365.  
  3366.   hostname_list_initialized = 0;
  3367. }
  3368.  
  3369. sv_allow_null_glob_expansion (name)
  3370.      char *name;
  3371. {
  3372.   allow_null_glob_expansion = (int)find_variable (name);
  3373. }
  3374.  
  3375. #if defined (GETOPTS_BUILTIN)
  3376. sv_optind (name)
  3377.      char *name;
  3378. {
  3379.   char *tt = get_string_value ("OPTIND");
  3380.   int s = 0;
  3381.  
  3382.   if (tt && *tt)
  3383.     {
  3384.       s = atoi (tt);
  3385.  
  3386.       /* According to POSIX, setting OPTIND=1 resets the internal state
  3387.      of getopt (). */
  3388.       if (s < 0 || s == 1)
  3389.     s = 0;
  3390.     }
  3391.   getopts_reset (s);
  3392. }
  3393.  
  3394. int
  3395. sv_opterr (name)
  3396.      char *name;
  3397. {
  3398.   char *tt = get_string_value ("OPTERR");
  3399.   int s = 1;
  3400.   extern int opterr;
  3401.  
  3402.   if (tt)
  3403.     s = atoi (tt);
  3404.   opterr = s;
  3405.   return (0);
  3406. }
  3407. #endif /* GETOPTS_BUILTIN */
  3408.